I've seen Ruby code with classes called like methods:
FactoryGirl(:factory_name) # => returns a factory instance
How do you write that 'method'?
All you need to do is to create a function with the same name as the class and that forwards its parameters to the class' new method. For instance:
class Foo
def initialize(x)
#arg=x
end
def to_s
#arg.to_s
end
end
def Foo(x)
Foo.new(x)
end
a = Foo.new(7)
a.class
=> Foo
puts a
=> 7
b = Foo(7)
b.class
=> Foo
puts b
=> 7
For completeness, it's defined in lib/factory_girl/syntax/vintage.rb at the bottom:
module FactoryGirl
module Syntax
module Vintage
# [other stuff elided]
# Shortcut for Factory.create.
#
# Example:
# Factory(:user, name: 'Joe')
def Factory(name, attrs = {})
ActiveSupport::Deprecation.warn 'Factory(:name) is deprecated; use FactoryGirl.create(:name) instead.', caller
FactoryGirl.create(name, attrs)
end
end
end
end
You can add this factory-function to the Object-class:
class Object
def FactoryGirl(symbol)
...
end
end
Related
I wrote some code to learn about the class_eval method. My understanding is that Foo.class_eval will set self to "Foo" and evaluate the block below in that context, just as saying "class Foo" will do. However, the code below shows that setting a class variable using class_eval will assign the class variable at the toplevel: to "Object". Why does this happen?
class Foo
end
class Foo
puts self
# => Foo
##class_var = "hello"
end
puts Object.class_variables
# => []
Foo.class_eval do
puts self
# => Foo
##class_var = "hi"
# => warning: class variable access from toplevel
end
puts Object.class_variables
# => ##class_var
As pointed out in comments a single # would do what you want, now if you were running the code from inside another class ## would work but it would set a class variable for both Foo, and whatever class you running from:
class Foo
puts self
# => Foo
##class_var = "hello"
end
class Bar
def self.main
puts Object.class_variables
# => []
Foo.class_eval do
puts self
# => Foo
##class_var = "hi"
end
end
end
Bar.main
p [Bar.class_variables]
#[[:##class_var]]
p [Foo.class_variables]
#[[:##class_var]]
That has to do with proc or block scope, I was expecting it to set only ##class_var only on Bar class but it actually sets on both, weird.
I'm fairly new to Ruby metaprogramming. I'm trying to write code which generates the
"dup" function for a class when it's created, using a list of fields which should be passed into the constructor. However, I can't figure out how to get access to the name of the class I'm creating, while I'm creating it.
So for example, if I had this code:
class Example
make_dup :name, :value
attr_accessor :name, :value
def initialize(name,value)
#name, #value = name, value
end
end
I'd want it to create the method:
def dup
Example.new(name,value)
end
I'm just getting stuck on how it would figure out to insert Example there.
Note that all classes have built-in dup and clone methods. You can customize what happens in them by adding an initialize_copy method, e.g.:
class Foo
attr_accessor :bar
def initialize_copy(orig)
super
#bar = #bar.dup
end
end
In case that isn't what you're truly looking for, you can access an object's class using its class method:
class Foo
def p_class
p self.class # Foo.new.p_class => Foo ; self is *a* `Foo'
end
def self.p_class
p self.class # Foo.p_class => Class ; self *is* `Foo'
end
end
def dup
self.class.new(name,value)
end
Maybe you can implement it this way:
module MyDup
def make_dup(*args)
define_method(:my_dup) do
obj = self.class.new(nil, nil)
args.each do |arg|
obj.send(arg.to_s + "=", self.send(arg))
end
obj
end
end
end
class Example
extend MyDup
make_dup :name, :value
attr_accessor :name, :value
def initialize(name,value)
#name, #value = name, value
end
end
e = Example.new("John", 30)
p e
d = e.my_dup
p d
Execution result as follows:
#<Example:0x000000022325d8 #name="John", #value=30>
#<Example:0x00000002232358 #name="John", #value=30>
I am using g a logger in all of my classes.
I want each msg to begin with class name and method name like so:
Class_name::Method_name
this is what i'm doing now :
class FOO
def initialize
end
def bar
msg_prefix = "#{self.class}::#{__method__}"
... some code ...
#logeer = "#{msg_prefix} msg ..."
end
def bar2
msg_prefix = "#{self.class}::#{__method__}"
... some code 2 ...
#logeer = "#{msg_prefix} msg2 ..."
end
end
i want to use a before_filter like in rails to prevent duplicity,
I am using sinatra but the classes are plain old ruby 1.9.3 classes
ideas??
You can get a callback on any method being created with Module#method_added, alias the old method, then define a new method that calls the before_filter method first. Here's my (extremely) rough first concept:
module Filter
def before_filter name
##filter = name
end
def method_added name
return if #filtering # Don't add filters to original_ methods
return if ##filter == name # Don't filter filters
return if name == :initialize
#filtering = true
alias_method :"original_#{name}", name
define_method name do |*args|
self.send ##filter, name
self.send :"original_#{name}", *args
end
#filtering = false
end
end
class FilterTest
extend Filter
before_filter :prepare_logs
def baz
puts "#{#msg_prefix} message goes here"
end
def prepare_logs name
#msg_prefix = "#{self.class}::#{name}"
end
end
ft = FilterTest.new
ft.baz
By using __method__ like you were in create_prefix, you'll get the name of the filter method, not the original method, so you have to pass the method name in. There might be other solutions to make that a bit cleaner.
You can use ActiveModel::Callbacks to get before_filter-like behaviour in plain Ruby classes (though perhaps in your case it's overkill for just executing one line):
require 'active_model'
class FOO
extend ActiveModel::Callbacks
define_model_callbacks :baz, only: :before
before_baz :create_prefix
def initialize
end
def bar
run_callbacks :baz do
... some code ...
#logeer = "#{#msg_prefix} msg ..."
end
end
def bar2
run_callbacks :baz do
... some code 2 ...
#logeer = "#{#msg_prefix} msg2 ..."
end
end
private
def create_prefix
#msg_prefix = "#{self.class}::#{__method__}"
end
end
I am trying to define some classes in Ruby that have an inheritance hierarchy, but I want to use one of the methods in the base class in the derived class. The twist is that I don't want to call the exact method I'm in, I want to call a different one. The following doesn't work, but it's what I want to do (basically).
class A
def foo
puts 'A::foo'
end
end
class B < A
def foo
puts 'B::foo'
end
def bar
super.foo
end
end
Probably, this is what you want?
class A
def foo
puts 'A::foo'
end
end
class B < A
alias bar :foo
def foo
puts 'B::foo'
end
end
B.new.foo # => B::foo
B.new.bar # => A::foo
A more general solution.
class A
def foo
puts "A::foo"
end
end
class B < A
def foo
puts "B::foo"
end
def bar
# slightly oddly ancestors includes the class itself
puts self.class.ancestors[1].instance_method(:foo).bind(self).call
end
end
B.new.foo # => B::foo
B.new.bar # => A::foo
I'm trying to make a method similar to attr_reader but I can't seem to get the instance of the class that the method gets called in.
class Module
def modifiable_reader(*symbols)
# Right here is where it returns Klass instead of #<Klass:0x1df25e0 #readable="this">
mod = self
variables = symbols.collect { |sym| ("#" << sym.to_s).to_sym }
attr_reader *symbols
(class << ModifyMethods; self; end).instance_eval do
define_method(*symbols) do
mod.instance_variable_get(*variables)
end
end
end
end
class Object
module ModifyMethods; end
def modify(&block)
ModifyMethods.instance_eval(&block)
end
end
class Klass
modifiable_reader :readable
def initialize
#readable = "this"
end
end
my_klass = Klass.new
my_klass.modify do
puts "Readable: " << readable.to_s
end
I'm not sure what it is you're trying to do.
If it helps, the spell for attr_reader is something like this:
#!/usr/bin/ruby1.8
module Kernel
def my_attr_reader(symbol)
eval <<-EOS
def #{symbol}
##{symbol}
end
EOS
end
end
class Foo
my_attr_reader :foo
def initialize
#foo = 'foo'
end
end
p Foo.new.foo # => "foo"
What I can understand from your code is that you want to have the modify block to respond to the instance methods of Klass, that's as simple as:
class Klass
attr_reader :modifiable
alias_method :modify, :instance_eval
def initialize(m)
#modifiable = m
end
end
Klass.new('john').modify do
puts 'Readable %s' % modifiable
end
About this tidbit of code:
def modifiable_reader(*symbols)
# Right here is where it returns Klass instead of #<Klass:0x1df25e0 #readable="this">
mod = self
...
Probably this can give you a hint of what is going on:
Class.superclass # => Module
Klass.instance_of?(Class) # => true
Klass = Class.new do
def hello
'hello'
end
end
Klass.new.hello # => 'hello'
When you are adding methods to the Module class, you are also adding methods to the Class class, which will add an instance method to instances of Class (in this case your class Klass), at the end this means you are adding class methods on your Klass class