Module: Maintain
- Defined in:
- lib/maintain.rb,
lib/maintain/value.rb,
lib/maintain/maintainer.rb,
lib/maintain/bitmask_value.rb,
lib/maintain/integer_value.rb
Defined Under Namespace
Classes: BitmaskValue, IntegerValue, Maintainer, Value
Constant Summary collapse
- VERSION =
'0.0.1'
Instance Method Summary collapse
-
#maintain(attribute, options = {}, &block) ⇒ Object
(also: #maintains)
The core class method of Maintain.
-
#maintainers ⇒ Object
:nodoc:.
Instance Method Details
#maintain(attribute, options = {}, &block) ⇒ Object Also known as: maintains
The core class method of Maintain. Basic usage is:
maintain :state do
state :new, :default => true
state :expired, :enter => :expire_children
state :reopened, :exit => lambda { children.each(&:reopen) }
aggregate :accessible, :as => [:new, :reopened]
end
It also supports more complex configuration options, like bitmask columns and integer values (for performance and portability)
maintain :permissions, :bitmask => true do
state :edit, 1
state :delete, 2
state :manage, 3
end
This method is aliased as maintains with the intention of allowing developers to code imperatively (“maintain, damn you!”) or descriptively (“it maintains, man”)
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/maintain.rb', line 29 def maintain(attribute, = {}, &block) # Detect if this is ActiveRecord::Base or a subclass of it # TODO: Make this not suck if defined?(ActiveRecord::Base) active_record = self == ActiveRecord::Base superclass = self while !active_record && superclass.superclass active_record = superclass == ActiveRecord::Base superclass = superclass.superclass end else active_record = false end # Create an instance of the maintainer class. It handles all of the state # configuration, hooking, aggregation, named_scoping, etc. maintainer = Maintainer.new(self, attribute, active_record, ) if block_given? maintainer.instance_eval(&block) end # Define our getters and setters - these are the only methods Maintain will stomp # on if you've already defined them. This is because they're how Maintain works. class_eval <<-EOC def #{attribute}=(value) # If we can find the maintainer on this attribute, we'll use it to set values. if maintainer = self.class.maintainers[#{attribute.to_sym.inspect}] # First, we instantiate a value on this maintainer if we haven't already @#{attribute} ||= maintainer.value # Then run the exit hook if we're changing the value maintainer.hook(:exit, @#{attribute}.value, self) # Then set the value itself. Maintainer::State will return the value you set, # so if we're setting to nil we get rid of the attribute entirely - it's not # needed and we want the getter to return nil in that case. unless @#{attribute}.set_value(value) @#{attribute} = nil end#{%{ # If this is ActiveRecord::Base or a subclass of it, we'll make sure calling the # setter writes a DB-friendly value. if respond_to?(:write_attribute) write_attribute(:#{attribute}, @#{attribute} ? @#{attribute}.value.to_s : nil) end } if active_record} # Last but not least, run the enter hooks for the new value - cause that's how we # do. maintainer.hook(:enter, @#{attribute}.value, self) if @#{attribute} else # If we can't find a maintainer for this attribute, make our best effort to do what # attr_accessor does - set the instance variable. @#{attribute} = value#{%{ # ... and on ActiveRecord::Base, we'll also write the attribute like a normal setter. if respond_to?(:write_attribute) write_attribute(:#{attribute}, @#{attribute}) end } if active_record} end end def #{attribute} # Start by returning an already-instantiated Maintainer::State if it exists return @#{attribute} if @#{attribute} # If'n it doesn't already exist AND this maintained attribute has a default value (and # bitmasks must have at least a 0 value), we'll instantiate a Maintainer::State and return # it. if self.class.maintainers[#{attribute.to_sym.inspect}].default? || self.class.maintainers[#{attribute.to_sym.inspect}].bitmask?#{" || attributes['#{attribute}']" if active_record} @#{attribute} = self.class.maintainers[#{attribute.to_sym.inspect}].value#{"(read_attribute(:#{attribute}))" if active_record} end end EOC # Last! Not least! Save our maintainer directly on this class. We'll use it in our setters (as in above) # and we'll also modify it instead of replacing it outright, so subclasses or mixins can extend functionality # without replacing it. maintainers[attribute.to_sym] = maintainer # # unless respond_to?(attribute) # class_eval <<-EOC # def #{attribute} # maintainers[#{attribute.to_sym.inspect}] # end # EOC # end end |
#maintainers ⇒ Object
:nodoc:
120 121 122 |
# File 'lib/maintain.rb', line 120 def maintainers #:nodoc: @maintainers ||= {} end |