Class: Class

Inherits:
Object show all
Defined in:
lib/jinx/helpers/class.rb

Instance Method Summary collapse

Instance Method Details

#alias_attribute(aliaz, attribute) ⇒ Object (private)

Creates an alias for each accessor method of the given attribute.

Examples:

class Person
 attr_reader :social_security_number
 attr_accessor :postal_code
 alias_attribute(:ssn, :social_security_number)
 alias_attribute(:zip_code, :postal_code)
end
Person.method_defined?(:ssn) #=> true
Person.method_defined?(:ssn=) #=> false
Person.method_defined?(:zip_code) #=> true
Person.method_defined?(:zip_code=) #=> true


30
31
32
33
34
# File 'lib/jinx/helpers/class.rb', line 30

def alias_attribute(aliaz, attribute)
  alias_method(aliaz, attribute) if method_defined?(attribute)
  writer = "#{attribute}=".to_sym
  alias_method("#{aliaz}=".to_sym, writer) if method_defined?(writer)
end

#attr_create_on_demand_accessor(symbol) {|obj| ... } ⇒ Object (private)

Defines an instance variable accessor attribute whose reader calls the block given to this method to create a new instance variable on demand, if necessary.

For example, the declaration

class AlertHandler
  attr_create_on_demand_accessor(:pings) { Array.new }
end

is equivalent to:

class AlertHandler
  attr_writer :pings
  def pings
    instance_variable_defined?(@pings) ? @pings : Array.new
  end
end

This method is useful either as a short-hand for the create-on-demand idiom as shown in the example above, or when it is desirable to dynamically add a mix-in attribute to a class at runtime whose name is not known when the class is defined.

Examples:

class AlertHandler
  def self.handle(alert)
    attr_create_on_demand_accessor(alert) { AlertQueue.new }
  end
end
...
AlertHandler.handle(:pings)
AlertHandler.new.pings #=> empty AlertQueue

Parameters:

  • symbol (Symbol)

    the attribute to define

Yields:

  • (obj)

    factory to create the new attribute value for the given instance

Yield Parameters:

  • obj

    the class instance for which the attribute will be set



94
95
96
97
98
99
100
101
102
# File 'lib/jinx/helpers/class.rb', line 94

def attr_create_on_demand_accessor(symbol)
  attr_writer(symbol)
  wtr = "#{symbol}=".to_sym
  iv = "@#{symbol}".to_sym
  # the attribute reader creates a new value on demand
  define_method(symbol) do
    instance_variable_defined?(iv) ? instance_variable_get(iv) : send(wtr, yield(self))
  end
end

#class_hierarchyObject

Returns an Enumerable on this class and its ancestors.



5
6
7
# File 'lib/jinx/helpers/class.rb', line 5

def class_hierarchy
  @class__hierarchy ||= Enumerable::Enumerator.new(self, :each_class_in_hierarchy)
end

#each_class_in_hierarchy {|klass| ... } ⇒ Object (private)

Enumerates each class in the hierarchy.

Yields:

  • (klass)

    the enumeration block

Yield Parameters:

  • klass (Class)

    the class in the hierarchy



108
109
110
111
112
113
114
# File 'lib/jinx/helpers/class.rb', line 108

def each_class_in_hierarchy
  current = self
  until current.nil?
    yield current
    current = current.superclass
  end
end

#offset_attr_accessor(hash, offset = nil) ⇒ Object (private)

Creates new accessor methods for each method => original hash entry. The new method offsets the existing Number original attribute value by the given offset (default -1).

Examples:

class OneBased
  attr_accessor :index
  offset_attr_accessor :zero_based_index => :index
end

Parameters:

  • hash ({Symbol => Symbol})

    the offset => original method hash

  • offset (Integer, nil) (defaults to: nil)

    the offset amount (default is -1)



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/jinx/helpers/class.rb', line 47

def offset_attr_accessor(hash, offset=nil)
  offset ||= -1
  hash.each do |method, original|
    define_method(method) { value = send(original); value + offset if value } if method_defined?(original)
    original_writer = "#{original}=".to_sym
    if method_defined?(original_writer) then
      define_method("#{method}=".to_sym) do |value|
        adjusted = value - offset if value
        send(original_writer, adjusted)
      end
    end
  end
end

#redefine_method(method) {|old_method| ... } ⇒ Symbol (private)

Redefines method using the given block. The block argument is a new alias for the old method. The block creates a proc which implements the new method body.

Examples:

redefine_method(:ssn) { |omth| lambda { send(omth).delete('-').to_i } }

Parameters:

  • method (Symbol)

    the method to redefine

Yields:

  • (old_method)

    the redefinition Proc

Yield Parameters:

  • old_method (Symbol)

    the method being redefined

Returns:

  • (Symbol)

    an alias to the old method implementation



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/jinx/helpers/class.rb', line 125

def redefine_method(method)
  # Make a new alias id method__base for the existing method.
  # Disambiguate with a counter suffix if necessary.
  counter = 2
  # Make a valid alias base. The base includes this class's object id in order
  # to ensure uniqueness within the class hierarchy. This alias uniqueness
  # guards against a superclass occluding a subclass redefinition.
  old, eq = /^([^=]*)(=)?$/.match(method.to_s).captures
  old.tr!('|', 'or')
  old.tr!('&', 'and')
  old.tr!('+', 'plus')
  old.tr!('*', 'mult')
  old.tr!('/', 'div')
  old.gsub!(/[^\w]/, 'op')
  base = "redefined__#{object_id}_#{old}"
  # Make a unique method alias for the old method.
  old_sym = "#{base}#{eq}".to_sym
  while method_defined?(old_sym)
    old_sym = "#{base}#{counter}#{eq}".to_sym
    counter = counter + 1
  end
  # Alias the old method before it is replaced.
  alias_method(old_sym, method)
  # The body defines the new method given the old method.
  body = yield old_sym
  define_method(method, body)
  old_sym
end