Class: Doodle::DoodleInfo
- Inherits:
-
Object
- Object
- Doodle::DoodleInfo
- Defined in:
- lib/doodle/info.rb
Overview
place to stash bookkeeping info
Instance Attribute Summary collapse
-
#arg_order ⇒ Object
Returns the value of attribute arg_order.
-
#errors ⇒ Object
Returns the value of attribute errors.
-
#local_attributes ⇒ Object
Returns the value of attribute local_attributes.
-
#local_conversions ⇒ Object
Returns the value of attribute local_conversions.
-
#local_validations ⇒ Object
Returns the value of attribute local_validations.
-
#parent ⇒ Object
Returns the value of attribute parent.
-
#this ⇒ Object
Returns the value of attribute this.
-
#validation_on ⇒ Object
Returns the value of attribute validation_on.
Instance Method Summary collapse
-
#attributes(tf = true) ⇒ Object
returns array of Attributes - if tf == true, returns all inherited attributes - if tf == false, returns only those attributes defined in the current object/class.
-
#class_attributes ⇒ Object
return class level attributes.
-
#conversions(tf = true) ⇒ Object
returns hash of conversions - if tf == true, returns all inherited conversions - if tf == false, returns only those conversions defined in the current object/class.
-
#defer_validation(&block) ⇒ Object
turn off validation, execute block, then set validation to same state as it was before
defer_validation
was called - can be nested. -
#handle_error(name, *args) ⇒ Object
handle errors either by collecting in :errors or raising an exception.
-
#initial_values(tf = true) ⇒ Object
return hash of key => value pairs of initial values (where defined) - if tf == true, returns all inherited initial values - if tf == false, returns only those initial values defined in current object/class.
-
#initialize(object) ⇒ DoodleInfo
constructor
takes one param - the object being doodled.
-
#inspect ⇒ Object
hide from inspect.
-
#key_values(tf = true) ⇒ Object
returns array of [key, value] pairs including default values - if tf == true, returns all inherited [key, value] pairs (default) - if tf == false, returns only those [key, value] pairs defined in current object.
-
#key_values_without_defaults(tf = true) ⇒ Object
returns array of [key, value] pairs excluding default values - if tf == true, returns all inherited [key, value] pairs (default) - if tf == false, returns only those [key, value] pairs defined in current object.
-
#keys(tf = true) ⇒ Object
returns array of attribute names - if tf == true, returns all inherited attribute names (default) - if tf == false, returns only those attribute names defined in current object.
-
#lookup_attribute(name) ⇒ Object
find an attribute.
-
#parents ⇒ Object
provide an alternative inheritance chain that works for singleton classes as well as modules, classes and instances.
-
#update(*args, &block) ⇒ Object
helper function to initialize from hash - this is safe to use after initialization (validate! is called if this method is called after initialization).
-
#validations(tf = true) ⇒ Object
access list of validations.
-
#values(tf = true) ⇒ Object
returns array of values (including defaults) - if tf == true, returns all inherited values (default) - if tf == false, returns only those values defined in current object.
Constructor Details
#initialize(object) ⇒ DoodleInfo
takes one param - the object being doodled
15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/doodle/info.rb', line 15 def initialize(object) @this = object @local_attributes = Doodle::OrderedHash.new @local_validations = [] @validation_on = true @local_conversions = {} @arg_order = [] @errors = [] #@parent = nil @parent = Doodle.parent end |
Instance Attribute Details
#arg_order ⇒ Object
Returns the value of attribute arg_order.
10 11 12 |
# File 'lib/doodle/info.rb', line 10 def arg_order @arg_order end |
#errors ⇒ Object
Returns the value of attribute errors.
11 12 13 |
# File 'lib/doodle/info.rb', line 11 def errors @errors end |
#local_attributes ⇒ Object
Returns the value of attribute local_attributes.
6 7 8 |
# File 'lib/doodle/info.rb', line 6 def local_attributes @local_attributes end |
#local_conversions ⇒ Object
Returns the value of attribute local_conversions.
8 9 10 |
# File 'lib/doodle/info.rb', line 8 def local_conversions @local_conversions end |
#local_validations ⇒ Object
Returns the value of attribute local_validations.
7 8 9 |
# File 'lib/doodle/info.rb', line 7 def local_validations @local_validations end |
#parent ⇒ Object
Returns the value of attribute parent.
12 13 14 |
# File 'lib/doodle/info.rb', line 12 def parent @parent end |
#this ⇒ Object
Returns the value of attribute this.
5 6 7 |
# File 'lib/doodle/info.rb', line 5 def this @this end |
#validation_on ⇒ Object
Returns the value of attribute validation_on.
9 10 11 |
# File 'lib/doodle/info.rb', line 9 def validation_on @validation_on end |
Instance Method Details
#attributes(tf = true) ⇒ Object
returns array of Attributes
-
if tf == true, returns all inherited attributes
-
if tf == false, returns only those attributes defined in the current object/class
96 97 98 99 100 101 102 103 104 |
# File 'lib/doodle/info.rb', line 96 def attributes(tf = true) results = handle_inherited_hash(tf, :local_attributes) # if an instance, include the singleton_class attributes #p [:attributes, @this, @this.singleton_class, @this.singleton_class.methods(false), results] if !@this.kind_of?(Class) && @this.singleton_class.doodle.respond_to?(:attributes) results = results.merge(@this.singleton_class.doodle.attributes) end results end |
#class_attributes ⇒ Object
return class level attributes
107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/doodle/info.rb', line 107 def class_attributes attrs = Doodle::OrderedHash.new if @this.kind_of?(Class) attrs = collect_inherited(:class_attributes).inject(Doodle::OrderedHash.new){ |hash, item| hash.merge(Doodle::OrderedHash[*item]) }.merge(@this.singleton_class.doodle.respond_to?(:attributes) ? @this.singleton_class.doodle.attributes : { }) attrs else @this.class.doodle.class_attributes end end |
#conversions(tf = true) ⇒ Object
returns hash of conversions
-
if tf == true, returns all inherited conversions
-
if tf == false, returns only those conversions defined in the current object/class
148 149 150 |
# File 'lib/doodle/info.rb', line 148 def conversions(tf = true) handle_inherited_hash(tf, :local_conversions) end |
#defer_validation(&block) ⇒ Object
turn off validation, execute block, then set validation to same state as it was before defer_validation
was called - can be nested
192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/doodle/info.rb', line 192 def defer_validation(&block) #p [:defer_validation, self.validation_on, @this] old_validation = self.validation_on self.validation_on = false v = nil begin v = @this.instance_eval(&block) ensure self.validation_on = old_validation end @this.validate!(false) v end |
#handle_error(name, *args) ⇒ Object
handle errors either by collecting in :errors or raising an exception
39 40 41 42 43 44 45 46 47 |
# File 'lib/doodle/info.rb', line 39 def handle_error(name, *args) # don't include duplicates (FIXME: hacky - shouldn't have duplicates in the first place) if !errors.include?([name, *args]) errors << [name, *args] end if Doodle.raise_exception_on_error raise(*args) end end |
#initial_values(tf = true) ⇒ Object
return hash of key => value pairs of initial values (where defined)
-
if tf == true, returns all inherited initial values
-
if tf == false, returns only those initial values defined in current object/class
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/doodle/info.rb', line 155 def initial_values(tf = true) attributes(tf).select{|n, a| a.init_defined? }.inject({}) {|hash, (n, a)| #p [:initial_values, a.name] hash[n] = case a.init when NilClass, TrueClass, FalseClass, Fixnum, Float, Bignum, Symbol # uncloneable values #p [:initial_values, :special, a.name, a.init] a.init when DeferredBlock #p [:initial_values, self, DeferredBlock, a.name] begin @this.instance_eval(&a.init.block) rescue Object => e #p [:exception_in_deferred_block, e] raise end else if a.init.kind_of?(Class) #p [:initial_values, :class] a.init.new else #p [:initial_values, :clone, a.name] begin a.init.clone rescue Exception => e warn "tried to clone #{a.init.class} in :init option (#{e})" #p [:initial_values, :exception, a.name, e] a.init end end end hash } end |
#inspect ⇒ Object
hide from inspect
34 35 36 |
# File 'lib/doodle/info.rb', line 34 def inspect '' end |
#key_values(tf = true) ⇒ Object
returns array of [key, value] pairs including default values
-
if tf == true, returns all inherited [key, value] pairs (default)
-
if tf == false, returns only those [key, value] pairs defined in current object
287 288 289 |
# File 'lib/doodle/info.rb', line 287 def key_values(tf = true) keys(tf).zip(values(tf)) end |
#key_values_without_defaults(tf = true) ⇒ Object
returns array of [key, value] pairs excluding default values
-
if tf == true, returns all inherited [key, value] pairs (default)
-
if tf == false, returns only those [key, value] pairs defined in current object
294 295 296 |
# File 'lib/doodle/info.rb', line 294 def key_values_without_defaults(tf = true) keys(tf).reject{|k| @this.default?(k) }.map{ |k, a| [k, @this.send(k)]} end |
#keys(tf = true) ⇒ Object
returns array of attribute names
-
if tf == true, returns all inherited attribute names (default)
-
if tf == false, returns only those attribute names defined in current object
280 281 282 |
# File 'lib/doodle/info.rb', line 280 def keys(tf = true) attributes(tf).keys end |
#lookup_attribute(name) ⇒ Object
find an attribute
135 136 137 138 139 140 141 142 143 |
# File 'lib/doodle/info.rb', line 135 def lookup_attribute(name) # (look at singleton attributes first) # fixme[this smells like a hack to me] if @this.class == Class class_attributes[name] else attributes[name] end end |
#parents ⇒ Object
provide an alternative inheritance chain that works for singleton classes as well as modules, classes and instances
51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/doodle/info.rb', line 51 def parents anc = if @this.respond_to?(:ancestors) if @this.ancestors.include?(@this) @this.ancestors[1..-1] else # singletons have no doodle_parents (they're orphans) [] end else @this.class.ancestors end anc.select{|x| x.kind_of?(Class)} end |
#update(*args, &block) ⇒ Object
helper function to initialize from hash - this is safe to use after initialization (validate! is called if this method is called after initialization)
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/doodle/info.rb', line 209 def update(*args, &block) # p [:doodle_initialize_from_hash, :args, *args] defer_validation do # hash initializer # separate into array of hashes of form [{:k1 => v1}, {:k2 => v2}] and positional args key_values, args = args.partition{ |x| x.kind_of?(Hash)} #DBG: Doodle::Debug.d { [self.class, :doodle_initialize_from_hash, :key_values, key_values, :args, args] } #!p [self.class, :doodle_initialize_from_hash, :key_values, key_values, :args, args] # set up initial values with ~clones~ of specified values (so not shared between instances) #init_values = initial_values #!p [:init_values, init_values] # match up positional args with attribute names (from arg_order) using idiom to create hash from array of assocs #arg_keywords = init_values.merge(Hash[*(Utils.flatten_first_level(self.class.arg_order[0...args.size].zip(args)))]) arg_keywords = Hash[*(Utils.flatten_first_level(self.class.arg_order[0...args.size].zip(args)))] #!p [self.class, :doodle_initialize_from_hash, :arg_keywords, arg_keywords] # merge all hash args into one key_values = key_values.inject(arg_keywords) { |hash, item| #!p [self.class, :doodle_initialize_from_hash, :merge, hash, item] hash.merge(item) } #!p [self.class, :doodle_initialize_from_hash, :key_values2, key_values] # convert keys to symbols (note not recursively - only first level == doodle keywords) Doodle::Utils.symbolize_keys!(key_values) #DBG: Doodle::Debug.d { [self.class, :doodle_initialize_from_hash, :key_values2, key_values, :args2, args] } #!p [self.class, :doodle_initialize_from_hash, :key_values3, key_values] # create attributes key_values.keys.each do |key| #DBG: Doodle::Debug.d { [self.class, :doodle_initialize_from_hash, :setting, key, key_values[key]] } #p [self.class, :doodle_initialize_from_hash, :setting, key, key_values[key]] #p [:update, :setting, key, key_values[key], __doodle__.validation_on] if respond_to?(key) __send__(key, key_values[key]) else # raise error if not defined __doodle__.handle_error key, Doodle::UnknownAttributeError, "unknown attribute '#{key}' => #{key_values[key].inspect} for #{self} #{doodle.attributes.map{ |k,v| k.inspect}.join(', ')}", Doodle::Utils.doodle_caller end end # do init_values after user supplied values so init blocks can # depend on user supplied values # - don't reset values which are supplied in args #p [:getting_init_values, instance_variables] __doodle__.initial_values.each do |key, value| if !key_values.key?(key) && respond_to?(key) #p [:initial_values, key, value] __send__(key, value) end end if block_given? #p [:update, block, __doodle__.validation_on] #p [:this, self] instance_eval(&block) end end @this end |
#validations(tf = true) ⇒ Object
access list of validations
note: validations are handled differently to attributes and conversions because ~all~ validations apply (so are stored as an array), whereas attributes and conversions are keyed by name and kind respectively, so only the most recent applies
126 127 128 129 130 131 132 |
# File 'lib/doodle/info.rb', line 126 def validations(tf = true) if tf local_validations + collect_inherited(:local_validations) else local_validations end end |
#values(tf = true) ⇒ Object
returns array of values (including defaults)
-
if tf == true, returns all inherited values (default)
-
if tf == false, returns only those values defined in current object
273 274 275 |
# File 'lib/doodle/info.rb', line 273 def values(tf = true) attributes(tf).map{ |k, a| @this.send(k)} end |