Namespace is evaluated twice
I put the following code into my namespace definition:
puts caller
puts '~~~~'
and it is executed twice, I see two backtraces. Is this normal? The file itself is loaded only once.
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:120:in `instance_eval'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:120:in `block in evaluate_as_instance_with_configuration'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/util/lazy_block.rb:11:in `evaluate_from'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:127:in `evaluate_as_instance_with_configuration'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `block in nest'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `each'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `nest'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:172:in `block in namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/settings.rb:160:in `within_namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:169:in `namespace'
/opt/reports_data/app/controllers/data.rb:50:in `block in <class:Data>'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:120:in `instance_eval'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:120:in `block in evaluate_as_instance_with_configuration'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/util/lazy_block.rb:11:in `evaluate_from'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:127:in `evaluate_as_instance_with_configuration'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `block in nest'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `each'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `nest'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:172:in `block in namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/settings.rb:160:in `within_namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:169:in `namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:155:in `replay_step_on'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:147:in `block in add_setup'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:146:in `each'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:146:in `add_setup'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:42:in `block (2 levels) in override_all_methods!'
/opt/reports_data/app/controllers/data.rb:37:in `<class:Data>'
~~~~
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:120:in `instance_eval'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:120:in `block in evaluate_as_instance_with_configuration'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/util/lazy_block.rb:11:in `evaluate_from'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:127:in `evaluate_as_instance_with_configuration'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `block in nest'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `each'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `nest'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:172:in `block in namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/settings.rb:160:in `within_namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:169:in `namespace'
/opt/reports_data/app/controllers/data.rb:50:in `block in <class:Data>'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:120:in `instance_eval'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:120:in `block in evaluate_as_instance_with_configuration'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/util/lazy_block.rb:11:in `evaluate_from'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:127:in `evaluate_as_instance_with_configuration'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `block in nest'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `each'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api/instance.rb:107:in `nest'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:172:in `block in namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/settings.rb:160:in `within_namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:169:in `namespace'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:155:in `replay_step_on'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:105:in `block in replay_setup_on'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:104:in `each'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:104:in `replay_setup_on'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:97:in `mount_instance'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:86:in `block in mount'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:84:in `each_pair'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/dsl/routing.rb:84:in `mount'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:155:in `replay_step_on'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:147:in `block in add_setup'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:146:in `each'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:146:in `add_setup'
/usr/local/bundle/gems/grape-1.3.3/lib/grape/api.rb:42:in `block (2 levels) in override_all_methods!'
/opt/reports_data/app/controllers/api.rb:29:in `<class:API>'
~~~~
- it is evaluated in
/opt/reports_data/app/controllers/data.rb:37when the controller code is loaded. - also evaluated in
/opt/reports_data/app/controllers/api.rb:29when the controller is mounted withmount Controllers::Data
@alexandrz I agree it looks weird :disappointed:
require 'grape'
class AddressAPI < Grape::API
params do
requires :test, type: String
puts 'Address API'
end
post '/address' do
end
end
class API < Grape::API
version 'v1', using: :path
mount AddressAPI
end
Address API will be printed 2 times. The reason is here where every method call gets added to the setup variable. Considering AddressAPI, the setup variable will contain, params and post:
[
{method: 'params', args: args, block: block},
{method: 'get', args: args, block: block}
]
Then when AddressAPI gets mounted all method calls stored in the setup variable gets replayed on API there.
There is a memory leak issue related to this approach.
You might consider a native Ruby include method instead, more info there https://nesteryuk.info/2020/04/12/grape-include-is-still-better-for-code-splitting.html. It is cheaper, our project uses this approach for 6 years without any issues.