When creating models for the sequel database gem in ruby a syntax like this is used:
class Users < Sequel::Model(:users) # <= what method is getting called here?
# other stuff...
end
Where :users is the name of the table.
I would like to pass an argument to the base class like this when the child class is defined for one of my own classes, but I can't work out how to do it. I don't know what this syntax is called, and I couldn't find any examples of it in my googling. I tried looking at the source for Sequel::Model as well, but its such a big class I couldn't find the relevant section.
Does anyone how what this syntax is and how it works?
It's a common trick to make a normal class/module method call look like a parameterized type.
There is actually a module method Sequel::Model which takes a single argument and returns a class (see the source code).
Have you considered using the #inherited hook of Class?
http://ruby-doc.org/core-2.0.0/Class.html#method-i-inherited
From the docs in the link above:
class Foo
def self.inherited(subclass)
puts "New subclass: #{subclass}"
end
end
class Bar < Foo
end
class Baz < Bar
end
Related
I am a beginner in ruby.
I've tried to run this code and it shows run time error.
What's wrong with this code?
class Calc
attr_accessor :val1, :val2
def initialize (val1,val2)
#val1=val1
#val2=val2
end
end
a=Calc.new(2,3)
a.add_two_numbers(3)
def add_two_numbers(v3)
return #val1+#val2+v3
end
The method add_two_numbers is not defined on the class Calc, however you are using it as if it is. This is the problem.
I would presume you got a NoMethodError.
Update: As pointed out in the comments, in actuallity, the method is defined on the Object class by default, which then gets auto inherited into all classes, but as private. This actually means that you will be getting the error saying that a private method is being called. The fix remains the same, since the overarching problem is a confusion in how to define classes and their methods.
The fix would be to define the method on the class, by putting it in the class body.
class Calc
attr_accessor :val1, :val2
def initialize (val1,val2)
#val1=val1
#val2=val2
end
def add_two_numbers(v3)
return #val1+#val2+v3
end
end
So you are defining a method outside of a class (which is want we don't want)
def add_two_numbers(v3)
return #val1+#val2+v3
end
You always want to make sure that you keep your classes and you logic as two separate entities in terms of organization. By that I mean:
Your classes in one file (calc.rb):
**class Calc
attr_accessor :val1, :val2
def initialize (val1,val2)
#val1=val1
#val2=val2
end
def add_two_numbers(v3)
return #val1+#val2+v3
end
end**
And your logic to access calc.rb in another file. Use require relative to access the logic inside the class file:
require_relative"/calc.rb"
a=Calc.new(2,3)
a.add_two_numbers(3)
Tip: When I was learning ruby the best way to keep them in two separate files for better organization.That way you know you don't have a method somewhere outside of the class. This would avoid your "no method error"
How come in Ruby it's possible to directly have an if statement directly in the class declaration? AKA:
class ApplicationController < ActionController::Base
if foo
bar = "x"
end
end
I know there is some class instance variables, since the Class inherits from Object, is it the same thing?
I just need some clarification about this whole thing :)
Thanks!
How come in Ruby it's possible to directly have an if statement directly in the class declaration
Because it's not a class "declaration", it's a class body, i.e. it's executable code just like a method body, a block body, a loop body or a script body.
The body of a class declaration is code just like everything else in Ruby. That's how you can use methods like attr_accessor, private and include — those are all just methods of the class. It's part of Ruby's philosophy of pervasive object orientation.
Without any problem. Class declaration code normally gets executed, with self = class itself, no problem defining local variables such as foo. Just remember that you are not in the class instance, but in the class itself.
class ApplicationController < ActionController::Base
foo = true
if foo
bar = "x"
end
puts bar
end
Should print "x"
Rails has these cool properties that seem to be actually methods. For example:
class SomeController < ApplicationController
before_filter :authenticate!
end
What are these actually called and how would you create your own? For example, in one of my models I want to be able to have a dynamic property that selects an internal method for processing some results:
class MyModel < ActiveRecord::Base
active_method :some_class_method
end
How would I set this up so I can set active_method like that and be able to access the active_method symbol as an instance var?
Edit for elaboration:
So give this starter below, I need to figure out how to define "selected_method" so that it defines a accessor or instance variable so "called_selected_method" calls "method_b".
class MyClass
selected_method :method_b
def call_selected_method
end
private
def method_a
puts 'method_a'
end
def method_b
puts 'method_b'
end
end
c = MyClass.new
c.call_selected_method # should put 'method_b'
It's actually just a method call to a method defined on the class. before_filter is provided by a ruby Module, which is mixed in to ActionController.
Creating your own methods similar to before_filter is as easy as:
Define a class method on your Class
Call that method in any concrete implementations of your class.
Some example code:
class MyClass
class << self
def some_function(*args)
# your code here
end
end
some_function "foo"
end
If you wanted to abstract it further, you can put the class method in to a Module, and then include that module in to your class(es).
UPDATE:
In relation to your asking of how to get a call of some_function to set an instance variable on your class, you can't, as class methods cannot affect specific instances of that class.
I have to wonder, though... you're writing a method that will just act as a proxy to your other method, and would be hard-coded in to the class definition. That offers no benefit to you, and would just make your code redundantly complicated.
I'm designing/building a system of classes that all derive from a single base class.
The goal is to have easy-to-use inherited macro methods that look something like this:
class Something < A::Base
full_name 'Something that goes bump in the night.'
end
Any code should be able to ask the class for this information (or, likely, normalized/derived infomation) later on via class-level accessor method(s).
puts Something.full_name
# => "Some kind of calculated value that may or may not go bump in the night."
Given that A::Base includes/extends/somehow-otherwise-mixes-in both a module with the macro method that works something like this:
module MacroMethods
private
def full_name(full_name)
# non-trivial, one-time-only set-up code exists here in actual usage
end
end
and a module with the class-level accessor method that works something like this:
module AccessorMethods
public
def full_name
# a non-trivial, runtime-calculated value is returned here in actual usage
end
end
no matter how I mix them in, I'm continually running into naming conflicts (i.e. ‘wrong number of arguments (1 for 0) (ArgumentError)’) between the two.
Note: full_name is the simplest example of what is needed; other, more-complex macros/accessors ensure the non-flexible constraints of macro methods needing to be declared inside the class and needing to be set once-and-only-once.
My question is two-fold:
Is there a way to make this all work inside of the A::Base class?
Is this the right way to do this in Ruby? Is there a better way go about it, achieving the same result?
Options that have been considered:
Calling either the macro or accessor method(s) something else.
(e.g. in Something class: set_up_full_name 'Something that …')
Downside is that the naming is confusing and unconventional.
Making the accessor method(s) instance-level instead of class-level.
(e.g. puts a_something.full_name')
Downside is that the traits set up by the macros are inherent to the class, not to each instance (in some cases, only a reference to the class may be available, not an instance).
Creating a single method that handles both macro and accessor functionality.
(e.g. in A::Base class: def self.full_name(*args) …)
Downside is that the macro methods can no longer be private and the RDoc looks like sh*t.
Using abstact/virtual-ish methods instead.
(e.g. in Something class: def self.full_name; 'Something that …'; end)
Downside is that this is more code in sub-classes and is more of a Objective-C (or C++, or Java, …) thing than a good Ruby paradigm.
Slipp, I read your question carefully. There is no way you can have 2 different methods called full_name defined on the same object at the same time. BUT, you could do something like this:
module MacroMethods
private
def full_name(full_name)
# non-trivial, one-time-only set-up code exists here in actual usage
# this method can only be called once in the definition of any given class,
# because after the first call, it will be redefined!
extend AccessorMethods
end
end
module AccessorMethods
public
def full_name
# a non-trivial, runtime-calculated value is returned here in actual usage
end
end
class Base
extend MacroMethods
end
class Something < Base
full_name 'after this call, I will get a new full_name method!'
end
class SomethingElse < Base
full_name 'so will I!'
end
If you want to have class macros available to certain classes, then a common base class is not the Ruby solution. Instead, you create a module that extends the base classes with the functionality you want them to have:
module Extensions
def self.included(base_class)
base_class.extend ClassMethods
end
module ClassMethods
attr_accessor :full_name
end
end
class Something
include Extensions
self.full_name = "Something that goes bump in the night"
end
puts Something.full_name # => Something that goes bump in the night
thing = Something.new
puts thing.full_name # Error
This overrides a hook method in Extensions called Module#included that passes any class that includes the module as an argument. The new method then calls Object#extend on the base class to put the methods available in ClassMethods directly onto that class as class methods. This works the same way as defining class methods, but this runs dynamically. This frees you of needing to use your only base class on a class that provides macros. Note that the methods are not defined on instances of classes that include the module.
It looks like most of the other answers have the right idea, but are lacking the getter method for #full_name. This example might be what you're looking for:
class Thing
class << self
attr_writer :full_name
def full_name
"My full name is #{#full_name}"
end
end
end
With this you can do something like this:
> Thing.full_name = 'Thing Class'
=> "Thing Class"
> Thing.full_name
=> "My full name is Thing Class"
This seems needlessly complex. Why not just use an attribute on the parent class?
class Base
class << self
attr_accessor :full_name
end
end
class A < Base; end
class B < Base; end
A.full_name = "The full name of A"
B.full_name = "The full name of B"
puts A.full_name # "The full name of A"
puts B.full_name # "The full name of B"
i've got a module that wants to use data provided by the class that included it - but at the class level, not the instance level.
the goal is to have class 'metadata' provided to a module that the class includes, so that the module can use the metadata during the included call.
this works:
module Bar
def value
#value
end
def baz
puts "the value is: #{value}"
end
end
module Foo
def self.included(mod)
mod.extend(Bar)
mod.baz
end
end
class MyClass
#value = "my class defined this"
include Foo
end
the output of this code is
the value is: my class defined this
i'm not sure if the use of #value is good or not... it seems odd to me that i require this to be set before the include Foo happens, not from a technical perspective (i know why it's required to be done in this order) but from an idiomatic or usability perspective.
... is there a better way / more idiomatic way of accomplishing this?
If you really want to use the class metadata in the moment you're including a module, given the 'included' method runs on its own scope, it's best to have a class method providing the metadata to it.
Also, if the metadata is not going to be manipulated, its better to declare it as a constant.
module Bar
def self.included(base)
puts "the value is: #{base.metadata}"
end
end
class MyClass
VALUE = "MyClass metadata"
def self.metadata
VALUE
end
include Bar
end
class OtherClass
VALUE = "OtherClass metadata"
def self.metadata
VALUE
end
include Bar
end
Of course you can declare the metadata anyway you want, as long as its accessible by a class method to your Module.
Also, its not common to do these kind of metadata manipulation in the module's 'included' method and the necessity of ordering your statements on the class level is a bit brittle, so you might want to try to find a different solution to your original problem instead.
If you want to the class to pass an argument to the mixin, then why not use one of the Ruby constructs that actually does allow passing an argument?
class Object
private
def Bar(metadata)
Module.new do
include Bar
define_singleton_method(:included) do |base|
puts "the value is: #{metadata}"
end
end
end
end
module Bar
# put common behavior here
end
class MyClass
include Bar 'MyClass metadata'
end
class OtherClass
include Bar 'OtherClass metadata'
end
This is a pretty common idiom that is for example used by the delegate library in the stdlib.