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.
-
#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.
-
#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. -
#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
-
#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
- #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
-
#values(tf = true) ⇒ Object
returns array of values - if tf == true, returns all inherited values (default) - if tf == false, returns only those values defined in current object.
Constructor Details
#initialize(object) ⇒ DoodleInfo
Returns a new instance of DoodleInfo.
318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/doodle.rb', line 318 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.
314 315 316 |
# File 'lib/doodle.rb', line 314 def arg_order @arg_order end |
#errors ⇒ Object
Returns the value of attribute errors.
315 316 317 |
# File 'lib/doodle.rb', line 315 def errors @errors end |
#local_attributes ⇒ Object
Returns the value of attribute local_attributes.
310 311 312 |
# File 'lib/doodle.rb', line 310 def local_attributes @local_attributes end |
#local_conversions ⇒ Object
Returns the value of attribute local_conversions.
312 313 314 |
# File 'lib/doodle.rb', line 312 def local_conversions @local_conversions end |
#local_validations ⇒ Object
Returns the value of attribute local_validations.
311 312 313 |
# File 'lib/doodle.rb', line 311 def local_validations @local_validations end |
#parent ⇒ Object
Returns the value of attribute parent.
316 317 318 |
# File 'lib/doodle.rb', line 316 def parent @parent end |
#this ⇒ Object
Returns the value of attribute this.
309 310 311 |
# File 'lib/doodle.rb', line 309 def this @this end |
#validation_on ⇒ Object
Returns the value of attribute validation_on.
313 314 315 |
# File 'lib/doodle.rb', line 313 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
391 392 393 394 395 396 397 398 |
# File 'lib/doodle.rb', line 391 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
408 409 410 411 412 413 414 415 416 417 418 |
# File 'lib/doodle.rb', line 408 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 |
#collect_inherited(message) ⇒ Object
send message to all doodle_parents and collect results
366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/doodle.rb', line 366 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
447 448 449 |
# File 'lib/doodle.rb', line 447 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
483 484 485 486 487 488 489 490 491 492 493 494 |
# File 'lib/doodle.rb', line 483 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
339 340 341 342 343 344 345 346 347 |
# File 'lib/doodle.rb', line 339 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
378 379 380 381 382 383 384 385 386 |
# File 'lib/doodle.rb', line 378 def handle_inherited_hash(tf, method) if tf collect_inherited(method).inject(Doodle::OrderedHash.new){ |hash, item| hash.merge(Doodle::OrderedHash[*item]) }.merge(@this.doodle.__send__(method)) else @this.doodle.__send__(method) end end |
#initial_values(tf = true) ⇒ Object
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/doodle.rb', line 451 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 #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 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)
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 |
# File 'lib/doodle.rb', line 499 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} 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 #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 end end |
#inspect ⇒ Object
334 335 336 |
# File 'lib/doodle.rb', line 334 def inspect '' end |
#lookup_attribute(name) ⇒ Object
434 435 436 437 438 439 440 441 442 |
# File 'lib/doodle.rb', line 434 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
351 352 353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/doodle.rb', line 351 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
420 421 422 423 424 425 426 427 428 429 430 431 432 |
# File 'lib/doodle.rb', line 420 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 |
#values(tf = true) ⇒ Object
returns array of values
-
if tf == true, returns all inherited values (default)
-
if tf == false, returns only those values defined in current object
403 404 405 |
# File 'lib/doodle.rb', line 403 def values(tf = true) attributes(tf).map{ |k, a| @this.send(k)} end |