Class: Ditz::ModelObject
Defined Under Namespace
Classes: ModelError
Class Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
Returns a new instance of ModelObject.
18
19
20
21
22
|
# File 'lib/model.rb', line 18
def initialize
@values = {}
@serialized_values = {}
self.class.fields.map { |f, opts| @values[f] = [] if opts[:multi] }
end
|
Class Attribute Details
Returns the value of attribute fields.
101
102
103
|
# File 'lib/model.rb', line 101
def fields
@fields
end
|
.serialized_values ⇒ Object
Returns the value of attribute serialized_values.
101
102
103
|
# File 'lib/model.rb', line 101
def serialized_values
@serialized_values
end
|
Returns the value of attribute values.
101
102
103
|
# File 'lib/model.rb', line 101
def values
@values
end
|
Class Method Details
.changes_are_logged ⇒ Object
104
105
106
107
|
# File 'lib/model.rb', line 104
def self.changes_are_logged
define_method(:changes_are_logged?) { true }
field :log_events, :multi => true, :ask => false
end
|
.create_interactively(opts = {}) ⇒ Object
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
# File 'lib/model.rb', line 173
def self.create_interactively opts={}
o = self.new
args = opts[:args] || []
@fields.each do |name, field_opts|
val = if opts[:with] && opts[:with][name]
opts[:with][name]
elsif field_opts[:generator].is_a? Proc
field_opts[:generator].call(*args)
elsif field_opts[:generator]
o.send field_opts[:generator], *args
elsif field_opts[:ask] == false field_opts[:default] || (field_opts[:multi] ? [] : nil)
else
q = field_opts[:prompt] || name.to_s.capitalize
if field_opts[:multiline]
ask_multiline q
else
default = if field_opts[:default_generator].is_a? Proc
field_opts[:default_generator].call(*args)
elsif field_opts[:default_generator]
o.send field_opts[:default_generator], *args
elsif field_opts[:default]
field_opts[:default]
end
ask q, :default => default
end
end
o.send("#{name}=", val)
end
o
end
|
.field(name, opts = {}) ⇒ Object
add a new field to a model object
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
|
# File 'lib/model.rb', line 58
def self.field name, opts={}
@fields ||= [] raise ModelError, "field with name #{name} already defined" if @fields.any? { |k, v| k == name }
@fields << [name, opts]
if opts[:multi]
single_name = name.to_s.sub(/s$/, "") define_method "add_#{single_name}" do |obj|
array = send(name)
raise ModelError, "already has a #{single_name} with name #{obj.name.inspect}" if obj.respond_to?(:name) && array.any? { |o| o.name == obj.name }
changed!
@serialized_values.delete name
array << obj
end
define_method "drop_#{single_name}" do |obj|
return unless @values[name].delete obj
@serialized_values.delete name
changed!
obj
end
end
define_method "#{name}=" do |o|
changed!
@serialized_values.delete name
@values[name] = o
end
define_method "__serialized_#{name}=" do |o|
changed!
@values.delete name
@serialized_values[name] = o
end
define_method name do
return @values[name] if @values.member?(name)
@values[name] = deserialized_form_of name, @serialized_values[name]
end
end
|
.field_names ⇒ Object
99
|
# File 'lib/model.rb', line 99
def self.field_names; @fields.map { |name, opts| name } end
|
109
110
111
112
113
114
|
# File 'lib/model.rb', line 109
def self.from fn
returning YAML::load_file(fn) do |o|
raise ModelError, "error loading from yaml file #{fn.inspect}: expected a #{self}, got a #{o.class}" unless o.class == self
o.pathname = fn if o.respond_to? :pathname=
end
end
|
.inherited(subclass) ⇒ Object
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
# File 'lib/model.rb', line 28
def self.inherited subclass
YAML.add_domain_type(yaml_domain, subclass.yaml_other_thing) do |type, val|
o = subclass.new
val.each do |k, v|
m = "__serialized_#{k}="
if o.respond_to? m
o.send m, v
else
$stderr.puts "warning: unknown field #{k.inspect} in YAML for #{type}; ignoring"
end
end
o.unchanged!
o
end
end
|
.yaml_domain ⇒ Object
25
|
# File 'lib/model.rb', line 25
def self.yaml_domain; "ditz.rubyforge.org,2008-03-06" end
|
.yaml_other_thing ⇒ Object
26
|
# File 'lib/model.rb', line 26
def self.yaml_other_thing; name.split('::').last.dcfirst end
|
Instance Method Details
170
|
# File 'lib/model.rb', line 170
def changed!; @changed = true end
|
#changed? ⇒ Boolean
169
|
# File 'lib/model.rb', line 169
def changed?; @changed ||= false end
|
override these two to model per-field transformations between disk and memory.
convert disk form => memory form
48
49
50
|
# File 'lib/model.rb', line 48
def deserialized_form_of field, value
@serialized_values[field]
end
|
#each_modelobject ⇒ Object
depth-first search on all reachable ModelObjects. fuck yeah.
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
# File 'lib/model.rb', line 123
def each_modelobject
seen = {}
to_see = [self]
until to_see.empty?
cur = to_see.pop
seen[cur] = true
yield cur
cur.class.field_names.each do |f|
val = cur.send(f)
next if seen[val]
if val.is_a?(ModelObject)
to_see.push val
elsif val.is_a?(Array)
to_see += val.select { |v| v.is_a?(ModelObject) }
end
end
end
end
|
120
|
# File 'lib/model.rb', line 120
def inspect; to_s end
|
#log(what, who, comment) ⇒ Object
164
165
166
167
|
# File 'lib/model.rb', line 164
def log what, who,
add_log_event([Time.now, who, what, || ""])
self
end
|
#save!(fn) ⇒ Object
142
143
144
145
146
|
# File 'lib/model.rb', line 142
def save! fn
File.open(fn, "w") { |f| f.puts to_yaml }
self
end
|
convert memory form => disk form
53
54
55
|
# File 'lib/model.rb', line 53
def serialized_form_of field, value
@values[field]
end
|
116
117
118
|
# File 'lib/model.rb', line 116
def to_s
"<#{self.class.name}: " + self.class.field_names.map { |f| "#{f}: " + (@values[f].to_s || @serialized_values[f]).inspect }.join(", ") + ">"
end
|
#to_yaml(opts = {}) ⇒ Object
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
# File 'lib/model.rb', line 148
def to_yaml opts={}
YAML::quick_emit(object_id, opts) do |out|
out.map(taguri, nil) do |map|
self.class.fields.each do |f, fops|
v = if @serialized_values.member?(f)
@serialized_values[f]
else
@serialized_values[f] = serialized_form_of f, @values[f]
end
map.add f.to_s, v
end
end
end
end
|
#to_yaml_type ⇒ Object
27
|
# File 'lib/model.rb', line 27
def to_yaml_type; "!#{self.class.yaml_domain}/#{self.class.yaml_other_thing}" end
|
#unchanged! ⇒ Object
171
|
# File 'lib/model.rb', line 171
def unchanged!; @changed = false end
|