Module: Changes

Includes:
Gather
Defined in:
lib/changes.rb

Overview

Same as Gather, except that history is kept for changes, and on_change is called each time a property value changes.

Defined Under Namespace

Modules: ClassMethods Classes: Change

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gather

#[], #[]=, #each, #gather, #merge, #merge!, #properties, #start=, #to_a, #to_hash

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args) ⇒ Object

Add the property methods if they don’t already exist, and if dynamic is in effect, which is the default. If static is in effect, the normal method_missing behaviour will be invoked.



110
111
112
113
114
115
116
117
# File 'lib/changes.rb', line 110

def method_missing(sym, *args)
  if self.class.dynamic?
    self.class.property sym
    send( sym, *args )
  else
    super
  end
end

Instance Attribute Details

#change_historyObject



57
58
59
# File 'lib/changes.rb', line 57

def change_history
  @change_history ||= []
end

Class Method Details

.included(base) ⇒ Object



311
312
313
# File 'lib/changes.rb', line 311

def self.included( base )
  base.extend( ClassMethods )
end

Instance Method Details

#changed?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/changes.rb', line 39

def changed?
  changes.empty?
end

#changes(*symbols) ⇒ Object



43
44
45
46
47
48
49
# File 'lib/changes.rb', line 43

def changes( *symbols )
  if symbols.empty?
    @changes ||= {}
  else
    symbols.map{|x| changes[x] }
  end
end

#init_properties(hash, &block) ⇒ Object

should probably use an object creation hook to do this



34
35
36
37
# File 'lib/changes.rb', line 34

def init_properties( hash, &block )
  @changes = {}
  gather( hash, &block )
end

#initialize(hash = {}, &block) ⇒ Object



28
29
30
# File 'lib/changes.rb', line 28

def initialize( hash = {}, &block )
  init_properties( hash, &block )
end

#markObject

make a mark in the change history



62
63
64
65
66
# File 'lib/changes.rb', line 62

def mark
  new_changes = @changes.clone
  new_changes.each{|k,v| new_changes[k] = v.clone}
  change_history << new_changes
end

#on_change(property, old, new) ⇒ Object

called after the property has changed including classes should define this



53
54
# File 'lib/changes.rb', line 53

def on_change( property, old, new )
end

#preserve(*symbols) ⇒ Object

execute the block, undo the given symbols, and return the result of the executed block. If no symbols are given, just use mark and restore



85
86
87
88
89
90
91
92
93
94
# File 'lib/changes.rb', line 85

def preserve( *symbols )
  mark if symbols.empty?
  retval = yield
  if symbols.empty?
    restore
  else
    symbols.each {|symbol| undo( symbol ) }
  end
  retval
end

#property_namesObject

Return a collection of property symbols



120
121
122
# File 'lib/changes.rb', line 120

def property_names
  self.class.properties.to_a
end

#reset!(*properties) ⇒ Object

reset the passed properties, or all if none are specified



74
75
76
77
78
79
80
# File 'lib/changes.rb', line 74

def reset!( *properties )
  if properties.empty?
    @changes = {}
  else
    properties.each {|x| changes[x] = Change.new}
  end
end

#restoreObject

restore the last mark. Do not emit any changes.



69
70
71
# File 'lib/changes.rb', line 69

def restore
  @changes = change_history.pop unless change_history.empty?
end

#undo(symbol) ⇒ Object



96
97
98
99
100
101
102
103
104
# File 'lib/changes.rb', line 96

def undo( symbol )
  unless changes[symbol].old.empty?
    current = send( symbol )
    if changes[symbol] && changes[symbol].old
      eval "@#{symbol.to_s} = changes[:#{symbol.to_s}].old.pop"
    end
    current
  end
end