Module: AngryHash::Extension

Defined in:
lib/angry_hash/extension.rb

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extend_hash(hash, mod, parent_hash, block) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/angry_hash/extension.rb', line 52

def extend_hash(hash, mod, parent_hash, block)
  if !parent_hash.nil? && hash.nil?
    hash = AngryHash.new
  end

  hash.extend mod

  hash.__parent_hash = parent_hash if hash.respond_to?(:__parent_hash=)

  if block
    hash.instance_eval(&block)
  end

  hash
end

.included(base) ⇒ Object



4
5
6
7
8
9
10
11
12
13
# File 'lib/angry_hash/extension.rb', line 4

def included(base)
  base.extend ClassMethods

  base.module_eval do
    def self.extend_object(obj)
      super
      Extension.mark_extension(obj,self)
    end
  end
end

.mark_extension(hash, mod) ⇒ Object



15
16
17
18
19
20
21
22
23
24
# File 'lib/angry_hash/extension.rb', line 15

def mark_extension(hash,mod)
  #puts "mark_extension hash=#{hash.class} mod=#{mod}"
  
  if (previous_mod = hash.__angry_hash_extension) && previous_mod != mod
    raise "hash #{hash} has already been extended by a different AngryHash::Extension (was: #{previous_mod}, now: #{mod})"
  end
  hash.__angry_hash_extension = mod

  setup_extended_hash(hash,mod)
end

.mixin_registryObject

A record of extensions to fields of classes.



27
28
29
# File 'lib/angry_hash/extension.rb', line 27

def mixin_registry
  @mixin_registry ||= Hash.new {|h,k| h[k] = {}}
end

.mixin_to(parent_obj, field, obj) ⇒ Object



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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/angry_hash/extension.rb', line 73

def mixin_to(parent_obj, field, obj)
  extension = parent_obj.__angry_hash_extension

  if mixin = mixin_registry[extension][field.to_s]
    kind,mod,options = *mixin

    if options[:allow_nil] && obj.nil?
      return nil
    end

    if options.key?(:default) && obj.nil?
      obj = options[:default]
    end



    # the result of `extend_self` block
    extend_self = if (sub_ext = mixin_registry[mod]['*']) && sub_ext[0] == :block
                    sub_ext[1][:block]
                  end

    case kind
    when :single
      obj = extend_hash(obj,mod,parent_obj,extend_self)
    when :array
      # XXX - this is ok for now... we really need to typecheck, perhaps wrap in a smart-array
      obj ||= []
      obj = obj.map! {|elt| extend_hash(elt, mod, parent_obj, extend_self) }
    when :hash
      obj ||= {}
      obj.replace( obj.inject(AngryHash.new) {|h,(k,elt)|
        h[k] = extend_hash(elt,mod,parent_obj, extend_self)
        h
      })
    end
    
    
  end

  obj
end

.register_mixin(target_class, field, mod, options) ⇒ Object

Register a value extension



32
33
34
# File 'lib/angry_hash/extension.rb', line 32

def register_mixin(target_class,field,mod,options)
  mixin_registry[target_class][field.to_s] = [:single, mod, options]
end

.register_mixin_array(target_class, field, mod, options) ⇒ Object

Register an array extension



37
38
39
# File 'lib/angry_hash/extension.rb', line 37

def register_mixin_array(target_class, field, mod, options)
  mixin_registry[target_class][field.to_s] = [:array, mod, options]
end

.register_mixin_block(target_class, options) ⇒ Object

Register a block extension - applied to objects of the defining module. This is in contrast to the other mixin types which are applied to subordinate objects.



48
49
50
# File 'lib/angry_hash/extension.rb', line 48

def register_mixin_block(target_class, options)
  mixin_registry[target_class]['*'] = [:block, options]
end

.register_mixin_hash(target_class, field, mod, options) ⇒ Object

Register a hash extension



42
43
44
# File 'lib/angry_hash/extension.rb', line 42

def register_mixin_hash(target_class, field, mod, options)
  mixin_registry[target_class][field.to_s] = [:hash, mod, options]
end

.setup_extended_hash(hash, mod) ⇒ Object



68
69
70
71
# File 'lib/angry_hash/extension.rb', line 68

def setup_extended_hash(hash, mod)
  mod.fill_in_defaults(hash) if mod.respond_to?(:fill_in_defaults)
  hash
end

Instance Method Details

#[](key) ⇒ Object

Instance methods



118
119
120
# File 'lib/angry_hash/extension.rb', line 118

def [](key)
  Extension.mixin_to(self,key,super)
end

#__angry_hash_extensionObject



146
147
148
# File 'lib/angry_hash/extension.rb', line 146

def __angry_hash_extension
  @__angry_hash_extension
end

#__angry_hash_extension=(mod) ⇒ Object



142
143
144
# File 'lib/angry_hash/extension.rb', line 142

def __angry_hash_extension=(mod)
  @__angry_hash_extension = mod
end

#__parent_hashObject



138
139
140
# File 'lib/angry_hash/extension.rb', line 138

def __parent_hash
  @__parent_hash
end

#__parent_hash=(hash) ⇒ Object

AngryHash extension attributes These should be copied using ‘AngryHash.copy_extension` when duping



134
135
136
# File 'lib/angry_hash/extension.rb', line 134

def __parent_hash=(hash)
  @__parent_hash = hash
end

#dup_with_extensionObject



126
127
128
129
130
# File 'lib/angry_hash/extension.rb', line 126

def dup_with_extension
  dup.tap {|new_hash|
    AngryHash.copy_extension(self,new_hash)
  }
end

#idObject



122
123
124
# File 'lib/angry_hash/extension.rb', line 122

def id
  self['id']
end