Error message:
NameError: uninitialized constant FinancialFunctions::ComputationSteps::TwoBranchesPerPeriod::Strategy1
I'd like Rails to automatically look through the included Strategies module and see the class defined within it instead of just looking within TwoBranchesPerPeriod.
This is not a one-time problem and is part of a broader architecture restructuring. Solving this problem will help in many places throughout the codebase.
There are two specific solutions I'm not looking for:
Having a require or load statement at the top of the file, as I want Rails autoloading to be the core solution for this problem and not have to require several files.
Explicitly state the scope when initializing the class. I'm aware that simply calling Strategies::Strategy1.new will work, but this solution does not work for me because of the length of several classes. I'd like to simply define the dependencies at the top of the file with include statements, and have access to the methods/classes defined in the included modules.
I'm open to autoload statements in a file such as strategies.rb but from what I've test this does not work either.
app/lib/financial_functions/computation_steps/two_branches_per_period.rb:
module FinancialFunctions
module ComputationSteps
module TwoBranchesPerPeriod
include Strategies
def a_method
#The below line is resulting in the error
# NameError: uninitialized constant FinancialFunctions::ComputationSteps::TwoBranchesPerPeriod::Strategy1
a=Strategy1.new
end
end
end
end
/app/lib/financial_functions/computation_steps/strategies/strategy1.rb:
module FinancialFunctions
module ComputationSteps
module Strategies
class Strategy1
def initialize
puts "this should work"
end
end
end
end
I'd like to simply define the dependencies at the top of the file with
include statements, and have access to the methods/classes defined in
the included modules.
Your expectations are not realistic in Ruby. Ruby does not have a package system and includes is not equivalent to imports in languages such as Python or ES6.
As stated in the comments by #maxpleaner includes only copies the methods of the module.
So to do this you would have to define new constants in the consuming class/module:
module FinancialFunctions
module ComputationSteps
module TwoBranchesPerPeriod
include Strategies
Strategy1 = ComputationSteps::Strategies::Strategy1
def a_method
Strategy1.new
end
end
end
end
You can do this dynamically through the Module#included hook:
module Foo
module Bar
end
module Baz
end
def self.included(base)
self.constants.each do |c|
base.constant_set(c, self.constant_get(c))
end
end
end
module X
includes Foo
end
irb(main):002:0> X::Bar
=> Foo::Bar
But aside from being an fun example of meta-programming I don't really think its that wise as the there is no way to handle namespace conflicts. You could also construct a makeshift equivalent of an imports construct:
module Importer
def import(*constants, from:)
constants.each do |c|
const_set(c, from.const_get(c))
end
end
end
module Foo
module Bar
module A
end
module B
end
end
end
class Thing
extend Importer
import :A, :B, from: Foo::Bar
end
irb(main):001:0> Thing::A
=> Foo::Bar::A
irb(main):002:0> Thing::B
=> Foo::Bar::B
But this also smells like an example of fighting the language and will probably introduce more problems then it solves.
Related
I have a module with some "class" or "DSL" methods which at the moment looks like:
module Things
module ClassMethods
def thing id, title, **options
# ... create and register a thing ...
end
# ... more DSL methods ...
end
extend ClassMethods
# define project things
thing :ruby, "Ruby programming language"
thing :rails, "Ruby on Rails web framework"
thing :active_support, "ActiveSupport library"
end
So I define the DSL methods in the ClassMethods, extend the Things with ClassMethods then use the DSL in the module body. I've chosen the name ClassMethods following the convention I see though out rails, although the module is not an active record Concern.
Now I would like to separate the DSL definition from its usage, so I split the code into
lib/things/class_methods.rb:
module Things
module ClassMethods
def thing id, title, **options
# ... create and register a thing ...
end
# ... more DSL methods ...
end
end
and lib/things.rb:
require_relative "things/class_methods"
module Things
extend ClassMethods
# define project things
thing :ruby, "Ruby programming language"
thing :rails, "Ruby on Rails web framework"
thing :active_support, "ActiveSupport library"
end
But after this something breaks: the code works as intended the first time after restarting the rails server, but subsequent requests that use this module raise obscure errors or complain that DSL methods aren't defined or otherwise behave as if the DSL calls didn't do what they were supposed to. It feels as if the extend ClassMethods line picks up a wrong module ClassMethod, but then I don't understand why i works initially.
Any idea what exactly goes wrong with my approach and what's the best solution to the problem? Should I rename the DSL module so it doesn't clash with ClassMethods defined elsewhere in the framework? Or is there anything else I can do to keep using the name ClassMethods without a conflict?
Rails sometimes loses track of constants during autoloading and reloading and needs some help.
This can either be an explicit dependency:
# lib/things.rb
require_dependency 'things/class_methods' # <- tells Rails that we depend on this
require_relative 'things/class_methods'
module Things
extend ClassMethods
# ...
end
Or by using a fully qualified contant:
# lib/things.rb
require_relative 'things/class_methods'
module Things
extend ::Things::ClassMethods
# ...
end
It might be enough to use extend Things::ClassMethods, provided that you don't have another Things module nested under Things.
Which approach works, seems to depend on your class structure and autoloading configuration.
Have you tried to add the /lib directory to your application.rb file using the .autoload_paths method?
I read this post: Ruby modules - included do end block – but still don't get when you would use the self.included do ... end block in a module.
The post says that code in the block will be ran when you include the module, but what's the point of that if a module's sole purpose is to be included? Wouldn't that code need to be run anyway? That block doesn't need to be there in order for that code to be run, right?
What would be the difference between the two below:
module M
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
module ClassMethods
...
end
end
vs.
module M
def self.some_class_method
...
end
scope :disabled, -> { where(disabled: true) }
end
What's the difference between the two examples?
The first code block adds the class methods in ClassMethods to the including class and calls the scope method on it as well. The second one does neither of these things and will result in a NoMethodError because the module has no scope class method. self.some_class_method will not be available on the including class once the module is included.
For the full story on how module inclusion works in Ruby, read my answer here:
Inheriting class methods from modules / mixins in Ruby
What's the point of self.included if a module's sole purpose is to be included?
Inclusion is not the only purpose of modules. They are also used for other things such as namespacing or simply storing various class methods that are then callable on the module itself.
Why doesn't Ruby include class methods automatically?
Theoretically Ruby could automatically add all class methods defined in a module to the including class, but in practice that would be a bad idea, because you would not get to choose anymore whether you want to include class methods — all class methods would be included every time, whether or not they are intended to be included. Consider this example:
module M
def self.class_method
"foo"
end
def self.configure_module
# add configuration for this module
end
end
class C
include M
end
Here, the configure_module method is obviously not supposed to be added to C, as its purpose is to set the configuration for the module object. Yet, if we had auto-inclusion for class methods, you would not be able to prevent it from being included.
But all instance methods are already included! How is that okay then?
Instance methods in a module are only really useful if they are included into a class, since modules cannot have instances, only classes can. So in a module every instance method is expected to be included somewhere to work.
A "class" method on a module is different, because it can be called on the module itself, so it can be used just fine regardless of whether it's also added to the including class. That is why it is better that you have a choice there.
module M
# self.included is the hook which automatically runs when this module is included
def self.included(base)
puts 'this will be printed when this module will be included inside a class'
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
def print_object_class
self.class.name # here self will be the object of class which includes this module
end
module ClassMethods
def print_class_name
self.name # Here self would be the class which is including this module
end
end
end
I tried to modify the above module to help you understand how a module(concern) can be helpful in code reusability
self.included is a hook which runs automatically when a module is included inside a class.
any method declare in the module ClassMethods will become class methods for the class including this module
any method declare outside the module ClassMethods will become instance methods for the class including this module
For Ex suppose there is a class Product and you have included the module in it
class Product < ActiveRecord::Base
include M
puts 'after including M'
end
If you try this example in you rails console you will notice that as soon as the module M gets included in class Product included hook of module run and
this will be printed when this module will be included inside a class this is printed on console
after that after including M this will be printed on the console.
Also you can try following commands
Product.disabled # a scope with name 'disabled' is avaialble because of including the module M
Product.print_class_name # Outputs => 'Product' This method is available to class with the help of module M
Product.new.print_object_class #Outputs => 'Product'
It also offers reusability, include this module M in any class and that class gets access to all those methods described in the module.
Whereas your second example is a mere example of basic module
module N
def self.abc
puts 'basic module'
end
end
Now abc method define in module can be accessible using only this module
N.abc # outputs 'basic module'
class Product < ActiveRecord::Base
include N
end
Product.abc #raises exception, No method found on class Product
Product.new.abc #raises exception, No method found on object of class Product
I hope this may help you understand the concept of module better.
Please let me know if you still have any doubts.
What's the difference between
module A
def self.included(klass)
puts klass
end
end
and
module A
include ActiveSupport::Concern
included do
puts self
end
end
Which one is a better and which one to use when?
Both snippets produce the same result. However, there is a small but important difference.
The first code is pure Ruby. It means it will work without any dependency.
The second piece of code depends on ActiveSupport that is an external dependency. If you want to use it you need to include the gem in your project. In a Rails application, there is almost no overhead because the application already depends on ActiveSupport. But in a non-Rails application, it may not be convenient.
Moreover, ActiveSupport::Concern does a lot more than simply adding some syntactic sugar for the Ruby included hook. In fact, the primary scope of such module was to manage multiple dependencies between modules.
In the Rails codebase it's very common to define small piece of features into separate modules. A good example is ActiveSupport itself. However, you may have that the feature A may require some feature defined in the module B, so if you include B in your code, then the module should make sure to require and mix also A, otherwise your code will crash.
It also implements a very common pattern based on the included hook: class-level extensions. The following Ruby code
module A
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def bar
"bar"
end
end
end
class Foo
include A
end
Foo.bar
# => "bar"
becomes
module A
extend ActiveSupport::Concern
module ClassMethods
def bar
"bar"
end
end
end
class Foo
include A
end
Foo.bar
# => "bar"
My personal advice is to avoid using the ActiveSupport::Concern if
You don't need to use its advanced features
The code you are writing, can be easily written with a few code with no dependency on Concern
The app does not already include ActiveSupport as dependency
In your second piece of code, included is called once during when A is defined. It does not do anything unless you had defined included to do something. The block passed to included would have no effect unless you had overwritten included to take a block and do something with it. In short, your second piece of code does not make sense.
I am trying to be dry by moving common methods into a module or a class and have it included/inherited in new classes that are namespaced under different modules. If I have two classes namespaces under the same module, then I can call them without including module name as long as I am under the same namespace. But if i have a method included from different module than my namespace scope changes and I dont know why or how to avoid it.
For example. this code works and returns 'bar':
module Foo
class Bar
def test_it
Helper.new.foo
end
end
end
module Foo
class Helper
def foo
'bar'
end
end
end
Foo::Bar.new.test_it
but if I move out method test_it into a module, then it doesnt work anymore: NameError: uninitialized constant Mixins::A::Helper.
module Mixins; end
module Mixins::A
def self.included(base)
base.class_eval do
def test_it
Helper.new.foo
end
end
end
end
module Foo
class Bar
include Mixins::A
end
end
module Foo
class Helper
def foo
'bar'
end
end
end
Foo::Bar.new.test_it
Moreover if class_eval is evaling string instead of block, scope becomes Foo::Bar instead of Foo.
module Mixins; end
module Mixins::A
def self.included(base)
base.class_eval %q{
def test_it
Helper.new.foo
end
}
end
end
module Foo
class Bar
include Mixins::A
end
end
module Foo
class Helper
def foo
'bar'
end
end
end
Foo::Bar.new.test_it
anyone got ideas?
EDIT:
Thanks to Wizard and Alex, I ended up with this code which is not beautiful but does the job (note it is using Rails helper constantize):
module Mixins; end
module Mixins::A
def self.included(base)
base.class_eval do
def test_it
_nesting::Helper
end
def _nesting
#_nesting ||= self.class.name.split('::')[0..-2].join('::').constantize
end
end
end
end
module Foo
class Helper
end
class Bar
include Mixins::A
end
end
module Foo2
class Helper
end
class Bar
include Mixins::A
end
end
Foo::Bar.new.test_it #=> returns Foo::Helper
Foo2::Bar.new.test_it #=> returns Foo2::Helper
To understand this problem, you need to understand how constant lookup works in Ruby. It's not the same as method lookup. In this code:
module Mixins::A
def self.included(base)
base.class_eval do
def test_it
Helper.new.foo
end
end
end
end
Helper refers to a constant called "Helper" which is either in A, Mixins, or defined at the top level (ie. in Object), not a constant called "Helper" which is defined in Bar. Just because you class_eval this code with class Bar, doesn't change that. If you know the difference between "lexical binding" and "dynamic binding", then you can say that constant resolution in Ruby uses lexical binding. You are expecting it to use dynamic binding.
Remember that the block which you are passing to base.class_eval is compiled to bytecode once, and subsequently, every time the included hook is called, that same precompiled block (including the reference to Helper) is executed with a different class (base) as self. The interpreter does not parse and compile the block afresh every time you execute base.class_eval.
On the other hand, if you pass a String to class_eval, that string is parsed and compiled afresh every time the included hook runs. IMPORTANT: code which is evaled from a String is evaluated in a null lexical environment. That means that local variables from the surrounding method are not available to the code being evaled from the string. More to the point for you, it also means that the surrounding scope will not affect constant lookup from within the evaled code.
If you do want a constant reference to be resolved dynamically, an explicit constant reference will never work. That's simply not the way the language is intended to work (and for good reason). Think about it: if constant references were resolved dynamically, depending on the class of self, you could never predict how references to things like Array or Hash would be resolved at runtime. If you has code like this in a module...
hash = Hash[array.map { |x| ... }]
...And the module was mixed in to a class with a nested Hash class, Hash.[] would refer to the nested class rather than Hash from the standard library! Clearly, resolving constant references dynamically has just too much potential for name clashes and related bugs.
Now with method lookup, that's a different thing. The whole concept of OOP (at least the Ruby flavor of OOP) is that what a method call (ie. a message) does depends on the class of the receiver.
If you do want to find a constant dynamically, depending on the class of the receiver, you can do it using self.class.const_get. This is arguably cleaner than evaling a String to achieve the same effect.
module Mixins::A
def self.included(base)
base.class_eval do
def test_it
Foo::Helper.new.foo
EDIT:
After getting a chance to play around with code a bit I see more of the problem. I don't think you'll be able to do exactly what you were attempting, but this is close:
module Mixins::A
def self.included(base)
base.class_eval do
def test_it
self.class.const_get(:Helper).new.foo
end
end
end
end
module Foo
class Bar
include Mixins::A
end
end
module Foo
class Bar::Helper
def foo
'bar'
end
end
end
Note that the Helper class needed to be namespaced under Foo::Bar due to way constants get resolved in Ruby.
Constant-lookup in Ruby has changed with respect to #class_eval over the past few major releases. See this post for more information: http://jfire.posterous.com/constant-lookup-in-ruby
I have a module saved in /lib as test_functions.rb that looks like this
module TestFunctions
def abc
puts 123
end
end
Going into ruby script/runner, I can see that the module is loading automatically (good ol' convention over configuration and all that...)
>> TestFunctions.instance_methods
=> ["abc"]
so the method is known, let's try calling it
>> TestFunctions.abc
NoMethodError: undefined method `abc' for TestFunctions:Module from (irb):3
Nope. How about this?
>> TestFunctions::abc
NoMethodError: undefined method `abc' for TestFunctions:Module from (irb):4
Test
Nope again.
defined?(TestFunctions::abc) #=> nil, but
TestFunctions.method_defined? :abc #=> true
Like I said at the top, I know I'm being dumb, can anyone de-dumb me?
If you want Module-level functions, define them in any of these ways:
module Foo
def self.method_one
end
def Foo.method_two
end
class << self
def method_three
end
end
end
All of these ways will make the methods available as Foo.method_one or Foo::method_one etc
As other people have mentioned, instance methods in Modules are the methods which are available in places where you've included the Module
I'm going to try to summarise the various answers myself, since each had something valuable to say, but none really got to what I now realise is probably the best response:
I was asking the wrong question because I was doing it wrong.
For reasons I can no longer explain, I wanted a set of completely stand-alone functions in a library, which represented methods I was trying to DRY out of my classes. That can be achieved, using things like
module Foo
def self.method_one
end
def Foo.method_two
end
class << self
def method_three
end
end
def method_four
end
module_function :method_four
end
I could also include my module, either within a class, in which case the methods become part of the class or outside, in which case they are defined on whatever class I'm running inside (Object? Kernel? Irb, if I'm interactive? Probably not a great idea, then)
The thing is, there was no good reason not to have a class in the first place - I'd somehow got on to a train of thought that took me down an seldom-used and frankly slightly weird branch line. Probably a flashback to the days before OO became mainstream (I'm old enough that up to today I've spent a lot more years writing procedural code).
So the functions have moved into a class, where they seem pretty happy, and the class methods thus exposed are being cheerfully used wherever necessary.
You can also use module_function like so:
module TestFunctions
def abc
puts 123
end
module_function :abc
end
TestFunctions.abc # => 123
Now you can include TestFunctions in class and call "abc" from within TestFunctions module.
I messed with this for a while and learned several things. Hopefully this will help someone else out. I am running Rails 3.2.8.
My module (utilities.rb) looks like this and is in the /lib directory of my rails app:
module Utilities
def compute_hello(input_string)
return "Hello #{input_string}"
end
end
My test (my_test.rb) looks like this and is in the /test/unit directory of my rails app:
require "test_helper"
require "utilities"
class MyTest < ActiveSupport::TestCase
include Utilities
def test_compute_hello
x = compute_hello(input_string="Miles")
print x
assert x=="Hello Miles", "Incorrect Response"
end
end
Here are a few things to note: My test extends ActiveSupport::TestCase. This is important because ActiveSupport adds /lib to the $LOAD_PATH. (seehttp://stackoverflow.com/questions/1073076/rails-lib-modules-and)
Secondly, I needed to both "require" my module file, and also "include" the module. Lastly, it is important to note that the stuff that gets included from the module essentially gets placed in the test class. So... be careful that the module that you include doesn't start with "test_". Otherwise, Rails will attempt to run your module method as a test.
You can't call a method in a Module directly. You need to include it in a class. Try this:
>> class MyTest
>> include TestFunctions
>> end
=> MyTest
>> MyTest.new.abc
123
=> nil
You need to include the module
include Testfunctions
Then 'abc' will return something.
You need to prefix your function with the module name because modules are not classes:
Your /lib/test_functions.rb:
module TestFunctions
def TestFunctions.abc
puts 123
end
end
Your code using the module method:
require 'test_functions'
TestFunctions.abc
Today you can do it using module_function notation.
module TestFunctions
def abc
puts 123
end
end
Now TestFunctions.abc prints "123"
A little more about module_function: https://apidock.com/ruby/Module/module_function
Try this code:
service = Class.new { extend TestFunctions }
service.method_four