class Object # Yields value to the passed block and returns the value. # The object passed in as the value parameter is also passed to the block # as a parameter. # # returning({}) do |hsh| # hsh.merge!((:bar => :baz)) # end #=> {:bar => :baz} def returning(value) yield(value) value end # Extracts the singleton class, so that metaprogramming can be done on it. # # Let's look at two code snippets: # # class MyString < String; end # # MyString.instance_eval do # define_method :foo do # puts self # end # end # # MyString.meta_class.instance_eval do # define_method :bar do # puts self # end # end # # def String.add_meta_var(var) # self.meta_class.instance_eval do # define_method var do # puts "HELLO" # end # end # end # # MyString.new("Hello").foo #=> "Hello" # MyString.new("Hello").bar #=> NoMethodError: undefined method `bar' for "Hello":MyString # MyString.foo #=> NoMethodError: undefined method `foo' for MyString:Class # MyString.bar #=> MyString # String.bar #=> NoMethodError: undefined method `bar' for String:Class # # MyString.add_meta_var(:x) # MyString.x #=> HELLO # # As you can see, using #meta_class allows you to execute code (and here, define # a method) on the metaclass itself. It also allows you to define class methods that can # be run on subclasses, and then be able to execute code on the metaclass of the subclass # (here MyString). # # In this case, we were able to define a class method (add_meta_var) on String that was # executable by the MyString subclass. It was then able to define a method on the subclass # by adding it to the MyString metaclass. # # For more information, you can check out _why's excellent article at: # http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html def meta_class() class << self; self end end # Runs instance_eval on the metaclass (see Object#meta_class). # # String.meta_eval do # define_method :zoo do # puts "zoo" # end # end # # String.zoo # => "zoo" def meta_eval(&blk) meta_class.instance_eval( &blk ) end # Defines a method on the metaclass (see Object#meta_class). # # String.meta_def :zoo do # puts "zoo" # end # # String.zoo #=> "zoo" # # If the class inherits from another class, it will only be defined # on the direct class meta_def is called on. # # class Foo; end # class Bar < Foo; end # class Baz < Foo; end # # Bar.meta_def :q do; "Q"; end # Foo.q #=> undefined method `r' for Foo:Class # Bar.q #=> "Q" # Baz.q #=> undefined method `r' for Baz:Class # # See Object#class_def for a comprehensive example containing meta_def def meta_def(name, &blk) meta_eval { define_method name, &blk } end # Defines a method on new instances of the class. # # String.class_def :zoo do # puts "zoo" # end # # "HELLO".zoo #=> "zoo" # # In combination with meta_def, you can do some pretty powerful # things: # # require 'merb_object' # class Foo # def self.var # @var # end # def self.make_var baz # attr_accessor baz # meta_def baz do |val| # @var = val # end # class_def :initialize do # instance_variable_set("@#{baz}", self.class.var) # end # end # end # # It might look a bit hairy, but here are some results that # may help: # # class Bar < Foo # make_var :foo # foo "FOO" # end # # Bar.new.foo #=> "FOO" # # Essentially, what's happening is that Foo.make_var has the # following effects when some symbol (:foo) is passed in: # * Adds a new :foo accessor (returning @foo) # * Adds a new foo method on the **class**, allowing you to set # a default value. # * Sets @foo to that default value when new objects are # initialized. # # In the case of the Bar class, the following occurred: # * make_var :foo created a new :foo accessor # * foo "FOO" set the default value of @foo to "FOO" # * Bar.new created a new Bar object containing the # instance variable @foo containing the default value # "FOO" def class_def name, &blk class_eval { define_method name, &blk } end # Returns true if: # * it's an empty array # * !self evaluates to true # # [].blank? #=> true # nil.blank? #=> true # false.blank? #=> true # [nil].blank? #=> false def blank? if respond_to?(:empty?) && respond_to?(:strip) empty? or strip.empty? elsif respond_to?(:empty?) empty? else !self end end def full_const_get(name) list = name.split("::") obj = Object list.each {|x| obj = obj.const_get(x) } obj end # An elegant way to refactor out common options # # with_options :order => 'created_at', :class_name => 'Comment' do |post| # post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all # post.has_many :unapproved_comments, :conditions => ['approved = ?', false] # post.has_many :all_comments # end # # Can also be used with an explicit reciever: # # map.with_options :controller => "people" do |people| # people.connect "/people", :action => "index" # people.connect "/people/:id", :action => "show" # end def with_options(options) yield Merb::OptionMerger.new(self, options) end end module Merb class OptionMerger #:nodoc: instance_methods.each do |method| undef_method(method) if method !~ /^(__|instance_eval|class)/ end def initialize(context, options) @context, @options = context, options end private def method_missing(method, *arguments, &block) merge_argument_options! arguments @context.send(method, *arguments, &block) end def merge_argument_options!(arguments) arguments << if arguments.last.respond_to? :to_hash @options.merge(arguments.pop) else @options.dup end end end end