Class: Doodle::DoodleInfo
- Inherits:
-
Object
- Object
- Doodle::DoodleInfo
- Defined in:
- lib/doodle.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.
-
#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.
-
#collect_inherited(message) ⇒ Object
send message to all doodle_parents and collect results.
-
#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 fixme: move. -
#handle_error(name, *args) ⇒ Object
handle errors either by collecting in :errors or raising an exception.
- #handle_inherited_hash(tf, method) ⇒ Object
-
#initial_values(tf = true) ⇒ Object
fixme: move.
-
#initialize(object) ⇒ DoodleInfo
constructor
A new instance of DoodleInfo.
-
#initialize_from_hash(*args) ⇒ Object
helper function to initialize from hash - this is safe to use after initialization (validate! is called if this method is called after initialization).
-
#inspect ⇒ Object
hide from inspect.
- #lookup_attribute(name) ⇒ Object
-
#parents ⇒ Object
provide an alternative inheritance chain that works for singleton classes as well as modules, classes and instances.
- #validations(tf = true) ⇒ Object
Constructor Details
#initialize(object) ⇒ DoodleInfo
Returns a new instance of DoodleInfo.
193 194 195 196 197 198 199 200 201 202 |
# File 'lib/doodle.rb', line 193 def initialize(object) @this = object @local_attributes = OrderedHash.new @local_validations = [] @validation_on = true @local_conversions = {} @arg_order = [] @errors = [] @parent = nil end |
Instance Attribute Details
#arg_order ⇒ Object
Returns the value of attribute arg_order.
189 190 191 |
# File 'lib/doodle.rb', line 189 def arg_order @arg_order end |
#errors ⇒ Object
Returns the value of attribute errors.
190 191 192 |
# File 'lib/doodle.rb', line 190 def errors @errors end |
#local_attributes ⇒ Object
Returns the value of attribute local_attributes.
185 186 187 |
# File 'lib/doodle.rb', line 185 def local_attributes @local_attributes end |
#local_conversions ⇒ Object
Returns the value of attribute local_conversions.
187 188 189 |
# File 'lib/doodle.rb', line 187 def local_conversions @local_conversions end |
#local_validations ⇒ Object
Returns the value of attribute local_validations.
186 187 188 |
# File 'lib/doodle.rb', line 186 def local_validations @local_validations end |
#parent ⇒ Object
Returns the value of attribute parent.
191 192 193 |
# File 'lib/doodle.rb', line 191 def parent @parent end |
#validation_on ⇒ Object
Returns the value of attribute validation_on.
188 189 190 |
# File 'lib/doodle.rb', line 188 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
261 262 263 264 265 266 267 268 |
# File 'lib/doodle.rb', line 261 def attributes(tf = true) results = handle_inherited_hash(tf, :local_attributes) # if an instance, include the singleton_class attributes 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
271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/doodle.rb', line 271 def class_attributes attrs = OrderedHash.new if @this.kind_of?(Class) attrs = collect_inherited(:class_attributes).inject(OrderedHash.new){ |hash, item| hash.merge(OrderedHash[*item]) }.merge(@this.singleton_class.doodle.respond_to?(:attributes) ? @this.singleton_class.doodle.attributes : { }) attrs else @this.class.doodle.class_attributes end end |
#collect_inherited(message) ⇒ Object
send message to all doodle_parents and collect results
236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/doodle.rb', line 236 def collect_inherited() result = [] parents.each do |klass| if klass.respond_to?(:doodle) && klass.doodle.respond_to?() result.unshift(*klass.doodle.__send__()) else break end end result 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
310 311 312 |
# File 'lib/doodle.rb', line 310 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 fixme: move
348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/doodle.rb', line 348 def defer_validation(&block) 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
209 210 211 212 213 214 215 216 217 |
# File 'lib/doodle.rb', line 209 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 |
#handle_inherited_hash(tf, method) ⇒ Object
248 249 250 251 252 253 254 255 256 |
# File 'lib/doodle.rb', line 248 def handle_inherited_hash(tf, method) if tf collect_inherited(method).inject(OrderedHash.new){ |hash, item| hash.merge(OrderedHash[*item]) }.merge(@this.doodle.__send__(method)) else @this.doodle.__send__(method) end end |
#initial_values(tf = true) ⇒ Object
fixme: move
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
# File 'lib/doodle.rb', line 315 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 # 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 #p [:initial_values, :clone, a.name] begin a.init.clone rescue Exception => e warn "tried to clone #{a.init.class} in :init option" #p [:initial_values, :exception, a.name, e] a.init end end hash } end |
#initialize_from_hash(*args) ⇒ Object
helper function to initialize from hash - this is safe to use after initialization (validate! is called if this method is called after initialization)
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
# File 'lib/doodle.rb', line 364 def initialize_from_hash(*args) #!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]] 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}", (caller) end end # do init_values after user supplied values so init blocks can depend on user supplied values #p [:getting_init_values, instance_variables] __doodle__.initial_values.each do |key, value| if !key_values.key?(key) && respond_to?(key) __send__(key, value) end end end end |
#inspect ⇒ Object
hide from inspect
204 205 206 |
# File 'lib/doodle.rb', line 204 def inspect '' end |
#lookup_attribute(name) ⇒ Object
297 298 299 300 301 302 303 304 305 |
# File 'lib/doodle.rb', line 297 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
221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/doodle.rb', line 221 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 |
#validations(tf = true) ⇒ Object
283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/doodle.rb', line 283 def validations(tf = true) if tf # 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 local_validations + collect_inherited(:local_validations) else local_validations end end |