angry_mob 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +123 -0
  3. data/bin/mob +139 -0
  4. data/lib/angry_mob.rb +28 -0
  5. data/lib/angry_mob/act.rb +111 -0
  6. data/lib/angry_mob/act/scheduler.rb +143 -0
  7. data/lib/angry_mob/action.rb +11 -0
  8. data/lib/angry_mob/builder.rb +115 -0
  9. data/lib/angry_mob/extend.rb +10 -0
  10. data/lib/angry_mob/extend/array.rb +30 -0
  11. data/lib/angry_mob/extend/blank.rb +108 -0
  12. data/lib/angry_mob/extend/blankslate.rb +109 -0
  13. data/lib/angry_mob/extend/dictionary.rb +140 -0
  14. data/lib/angry_mob/extend/hash.rb +67 -0
  15. data/lib/angry_mob/extend/object.rb +21 -0
  16. data/lib/angry_mob/extend/pathname.rb +23 -0
  17. data/lib/angry_mob/extend/string.rb +8 -0
  18. data/lib/angry_mob/log.rb +28 -0
  19. data/lib/angry_mob/mob.rb +77 -0
  20. data/lib/angry_mob/mob_loader.rb +115 -0
  21. data/lib/angry_mob/node.rb +44 -0
  22. data/lib/angry_mob/notifier.rb +76 -0
  23. data/lib/angry_mob/target.rb +257 -0
  24. data/lib/angry_mob/target/arguments.rb +71 -0
  25. data/lib/angry_mob/target/call.rb +57 -0
  26. data/lib/angry_mob/target/default_resource_locator.rb +11 -0
  27. data/lib/angry_mob/target/defaults.rb +23 -0
  28. data/lib/angry_mob/target/mother.rb +66 -0
  29. data/lib/angry_mob/target/notify.rb +57 -0
  30. data/lib/angry_mob/target/tracking.rb +96 -0
  31. data/lib/angry_mob/ui.rb +247 -0
  32. data/lib/angry_mob/util.rb +11 -0
  33. data/lib/angry_mob/vendored.rb +8 -0
  34. data/lib/angry_mob/version.rb +3 -0
  35. data/vendor/angry_hash/Rakefile +17 -0
  36. data/vendor/angry_hash/VERSION +1 -0
  37. data/vendor/angry_hash/angry_hash.gemspec +47 -0
  38. data/vendor/angry_hash/examples/accessors_eg.rb +46 -0
  39. data/vendor/angry_hash/examples/creation_eg.rb +43 -0
  40. data/vendor/angry_hash/examples/dsl.eg.rb +18 -0
  41. data/vendor/angry_hash/examples/dup_eg.rb +86 -0
  42. data/vendor/angry_hash/examples/eg_helper.rb +24 -0
  43. data/vendor/angry_hash/examples/merge_eg.rb +135 -0
  44. data/vendor/angry_hash/lib/angry_hash.rb +215 -0
  45. data/vendor/angry_hash/lib/angry_hash/dsl.rb +44 -0
  46. data/vendor/angry_hash/lib/angry_hash/extension_tracking.rb +12 -0
  47. data/vendor/angry_hash/lib/angry_hash/merge_string.rb +58 -0
  48. data/vendor/json/COPYING +58 -0
  49. data/vendor/json/GPL +340 -0
  50. data/vendor/json/README +360 -0
  51. data/vendor/json/lib/json/common.rb +371 -0
  52. data/vendor/json/lib/json/pure.rb +77 -0
  53. data/vendor/json/lib/json/pure/generator.rb +443 -0
  54. data/vendor/json/lib/json/pure/parser.rb +303 -0
  55. data/vendor/json/lib/json/version.rb +8 -0
  56. data/vendor/thor/CHANGELOG.rdoc +89 -0
  57. data/vendor/thor/LICENSE +20 -0
  58. data/vendor/thor/README.rdoc +297 -0
  59. data/vendor/thor/Thorfile +69 -0
  60. data/vendor/thor/bin/rake2thor +86 -0
  61. data/vendor/thor/bin/thor +6 -0
  62. data/vendor/thor/lib/thor.rb +244 -0
  63. data/vendor/thor/lib/thor/actions.rb +275 -0
  64. data/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  65. data/vendor/thor/lib/thor/actions/directory.rb +91 -0
  66. data/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
  67. data/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
  68. data/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
  69. data/vendor/thor/lib/thor/base.rb +540 -0
  70. data/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
  71. data/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  72. data/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  73. data/vendor/thor/lib/thor/error.rb +30 -0
  74. data/vendor/thor/lib/thor/group.rb +271 -0
  75. data/vendor/thor/lib/thor/invocation.rb +180 -0
  76. data/vendor/thor/lib/thor/parser.rb +4 -0
  77. data/vendor/thor/lib/thor/parser/argument.rb +67 -0
  78. data/vendor/thor/lib/thor/parser/arguments.rb +150 -0
  79. data/vendor/thor/lib/thor/parser/option.rb +128 -0
  80. data/vendor/thor/lib/thor/parser/options.rb +169 -0
  81. data/vendor/thor/lib/thor/rake_compat.rb +66 -0
  82. data/vendor/thor/lib/thor/runner.rb +314 -0
  83. data/vendor/thor/lib/thor/shell.rb +83 -0
  84. data/vendor/thor/lib/thor/shell/basic.rb +239 -0
  85. data/vendor/thor/lib/thor/shell/color.rb +108 -0
  86. data/vendor/thor/lib/thor/task.rb +102 -0
  87. data/vendor/thor/lib/thor/util.rb +224 -0
  88. data/vendor/thor/lib/thor/version.rb +3 -0
  89. data/vendor/thor/spec/actions/create_file_spec.rb +170 -0
  90. data/vendor/thor/spec/actions/directory_spec.rb +131 -0
  91. data/vendor/thor/spec/actions/empty_directory_spec.rb +91 -0
  92. data/vendor/thor/spec/actions/file_manipulation_spec.rb +271 -0
  93. data/vendor/thor/spec/actions/inject_into_file_spec.rb +135 -0
  94. data/vendor/thor/spec/actions_spec.rb +292 -0
  95. data/vendor/thor/spec/base_spec.rb +263 -0
  96. data/vendor/thor/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
  97. data/vendor/thor/spec/core_ext/ordered_hash_spec.rb +115 -0
  98. data/vendor/thor/spec/fixtures/application.rb +2 -0
  99. data/vendor/thor/spec/fixtures/bundle/execute.rb +6 -0
  100. data/vendor/thor/spec/fixtures/bundle/main.thor +1 -0
  101. data/vendor/thor/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  102. data/vendor/thor/spec/fixtures/doc/README +3 -0
  103. data/vendor/thor/spec/fixtures/doc/config.rb +1 -0
  104. data/vendor/thor/spec/fixtures/group.thor +90 -0
  105. data/vendor/thor/spec/fixtures/invoke.thor +112 -0
  106. data/vendor/thor/spec/fixtures/script.thor +145 -0
  107. data/vendor/thor/spec/fixtures/task.thor +10 -0
  108. data/vendor/thor/spec/group_spec.rb +171 -0
  109. data/vendor/thor/spec/invocation_spec.rb +107 -0
  110. data/vendor/thor/spec/parser/argument_spec.rb +47 -0
  111. data/vendor/thor/spec/parser/arguments_spec.rb +64 -0
  112. data/vendor/thor/spec/parser/option_spec.rb +202 -0
  113. data/vendor/thor/spec/parser/options_spec.rb +292 -0
  114. data/vendor/thor/spec/rake_compat_spec.rb +68 -0
  115. data/vendor/thor/spec/runner_spec.rb +210 -0
  116. data/vendor/thor/spec/shell/basic_spec.rb +205 -0
  117. data/vendor/thor/spec/shell/color_spec.rb +41 -0
  118. data/vendor/thor/spec/shell_spec.rb +34 -0
  119. data/vendor/thor/spec/spec.opts +1 -0
  120. data/vendor/thor/spec/spec_helper.rb +54 -0
  121. data/vendor/thor/spec/task_spec.rb +69 -0
  122. data/vendor/thor/spec/thor_spec.rb +237 -0
  123. data/vendor/thor/spec/util_spec.rb +163 -0
  124. data/vendor/thor/thor.gemspec +120 -0
  125. metadata +199 -0
@@ -0,0 +1,47 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{angry_hash}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Lachie Cox"]
12
+ s.date = %q{2010-08-07}
13
+ s.description = %q{A stabler mash with different emphases. Used in plus2 projects AngryMob and Igor.}
14
+ s.email = %q{lachie@plus2.com.au}
15
+ s.files = [
16
+ ".gitignore",
17
+ "Rakefile",
18
+ "VERSION",
19
+ "angry_hash.gemspec",
20
+ "examples/accessors_eg.rb",
21
+ "examples/creation_eg.rb",
22
+ "examples/dsl.eg.rb",
23
+ "examples/dup_eg.rb",
24
+ "examples/eg_helper.rb",
25
+ "examples/merge_eg.rb",
26
+ "lib/angry_hash.rb",
27
+ "lib/angry_hash/dsl.rb",
28
+ "lib/angry_hash/extension_tracking.rb",
29
+ "lib/angry_hash/merge_string.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/plus2/angry_hash}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.6}
35
+ s.summary = %q{A stabler mash with different emphases.}
36
+
37
+ if s.respond_to? :specification_version then
38
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
42
+ else
43
+ end
44
+ else
45
+ end
46
+ end
47
+
@@ -0,0 +1,46 @@
1
+ require 'eg_helper'
2
+
3
+ eg.setup do
4
+ @a = AngryHash[
5
+ :b => {
6
+ :c => 'c',
7
+ :d => 'd'
8
+ }
9
+ ]
10
+ end
11
+
12
+ def same_obj(a,b)
13
+ a.__id__ == b.__id__
14
+ end
15
+
16
+ eg 'accessor! with existing subhash' do
17
+ Assert( same_obj( @a.b!, @a.b ) )
18
+ end
19
+
20
+ eg 'accessor! creating and returning' do
21
+ d = @a.d!
22
+ Assert( same_obj( d, @a.d ) )
23
+ end
24
+
25
+ eg 'accessor= AngryHash' do
26
+ d = AngryHash.new
27
+ @a.d = d
28
+ Assert( same_obj( d, @a.d ) )
29
+ end
30
+
31
+ eg 'accessor= Hash' do
32
+ d = {}
33
+ @a.d = d
34
+ Assert( ! same_obj( d, @a.d ) )
35
+ end
36
+
37
+ eg 'accessor?' do
38
+ Assert( @a.b? )
39
+ Assert( ! @a.c? )
40
+ Assert( @a.b.c? )
41
+ Assert( ! @a.b.x? )
42
+
43
+ @a.b.f = false
44
+
45
+ Assert( ! @a.b.f? )
46
+ end
@@ -0,0 +1,43 @@
1
+ require 'eg_helper'
2
+
3
+ eg.helpers do
4
+ def oids(v)
5
+ sub = case v
6
+ when Hash
7
+ hh = {}
8
+ v.each {|kk,vv| hh[kk] = oids(vv)}
9
+ hh
10
+ when Array
11
+ v.map {|vv| oids(vv)}
12
+ else
13
+ v
14
+ end
15
+
16
+ n = {:class => v.class, :oid => v.__id__, :sub => sub}
17
+ if v.respond_to?(:__id__)
18
+ n[:oid] = v.__id__
19
+ else
20
+ n[:oid] = 0
21
+ end
22
+ n
23
+ end
24
+ end
25
+
26
+ eg 'creation duplicates' do
27
+ a1 = AngryHash[
28
+ :a => { :b => 1 },
29
+ :c => [ 1, :d, {:e => :f}, nil, true, false, 1.0, [ 'x', 'y' ] ]
30
+ ]
31
+ a2 = AngryHash[ a1 ]
32
+
33
+ pp oids(a1)
34
+ pp oids(a2)
35
+
36
+ Assert(a1.a.__id__ != a2.a.__id__)
37
+ Assert(a1.c[2].__id__ != a2.c[2].__id__)
38
+ Assert(a1.c[7].__id__ != a2.c[7].__id__)
39
+ end
40
+
41
+
42
+ #eg 'cycle detection' do
43
+ #end
@@ -0,0 +1,18 @@
1
+ require 'eg_helper'
2
+
3
+ eg 'eval a block as dsl' do
4
+ original = AngryHash[ :a => 'x', :b => {:c => 1}, :d => 'z' ]
5
+
6
+ original.__eval_as_dsl do
7
+ foo 'bar'
8
+ a 'y'
9
+ b :e => 2
10
+ end
11
+
12
+ Assert(original.foo == 'bar')
13
+ Assert(original.a == 'y')
14
+ Assert(original.d == 'z')
15
+
16
+ Assert(original.b.c == 1)
17
+ Assert(original.b.e == 2)
18
+ end
@@ -0,0 +1,86 @@
1
+ require 'eg_helper'
2
+
3
+ require 'angry_hash/extension_tracking'
4
+ AngryHash.send :include, AngryHash::ExtensionTracking
5
+
6
+ eg.setup do
7
+ @original = { 'database' => {
8
+ "micropower_micropower_sandbox" => {"app_owner" => "micropower_micropower_sandbox", "server" => :db},
9
+ "post_froggy" => {"app_owner" => "froggy_owner", "backup" => {"to_s3" => true}, "server" => :postfrog},
10
+ "myfrogdb" => {"app_owner" => :myfroggy, "server" => :myfrog},
11
+ "eggs_hwag" => {"app_owner" => "eggs_hwag", "backup" => {"to_s3" => true}, "server" => :db},
12
+ "isg_sandbox_v5" => {"app_owner" => "isg_sandbox_v5", "server" => :isg_forums_mysql},
13
+ }}
14
+ end
15
+
16
+ eg 'duping copies symbols' do
17
+ ah = AngryHash[ @original ]
18
+ ah2 = AngryHash[ ah ]
19
+
20
+ Assert( ! ah2.database.isg_sandbox_v5.server.nil? )
21
+ Assert( ah2.database.isg_sandbox_v5.server == @original['database']['isg_sandbox_v5']['server'] )
22
+ end
23
+
24
+ def same_obj(a,b)
25
+ a.__id__ == b.__id__
26
+ end
27
+
28
+ def diff_obj(a,b)
29
+ ! same_obj(a,b)
30
+ end
31
+
32
+ eg 'dup is deep' do
33
+ ah = AngryHash[ @original ]
34
+ ah2 = ah.dup
35
+
36
+ Assert( diff_obj ah , ah2 )
37
+ Assert( diff_obj ah.database , ah2.database )
38
+ Assert( diff_obj ah.database.post_froggy , ah2.database.post_froggy )
39
+ Assert( diff_obj ah.database.post_froggy.backup, ah2.database.post_froggy.backup )
40
+
41
+ end
42
+
43
+ module Extendo
44
+ def as_dag
45
+ dag = dup
46
+ dag
47
+ end
48
+
49
+ def is_extended?
50
+ true
51
+ end
52
+ end
53
+
54
+ eg 'duping from ext' do
55
+ ah = AngryHash[ @original ]
56
+ ah.extend(Extendo)
57
+
58
+ ah2 = ah.as_dag
59
+
60
+ Show( ah.__id__ )
61
+ Show( ah2.__id__ )
62
+
63
+ Show( ah2 )
64
+ end
65
+
66
+ module ExtendoDb
67
+ def is_db_extended?
68
+ true
69
+ end
70
+ end
71
+
72
+ eg 'extension preservation' do
73
+ ah = AngryHash[ @original ]
74
+ Assert( ! ah.is_extended? )
75
+ Assert( ! ah.database.post_froggy.is_db_extended? )
76
+
77
+ ah.extend(Extendo)
78
+ ah.database.post_froggy.extend(ExtendoDb)
79
+
80
+ Assert( ah.is_extended? )
81
+ Assert( ah.database.post_froggy.is_db_extended? )
82
+
83
+ ah2 = ah.dup
84
+ Show( ah2.is_extended? )
85
+ Show( ah2.database.post_froggy.is_db_extended? )
86
+ end
@@ -0,0 +1,24 @@
1
+ require 'pathname'
2
+ root = Pathname('../..').expand_path(__FILE__)
3
+ require 'pp'
4
+
5
+ UseGem = false
6
+
7
+ if UseGem
8
+ require 'rubygems'
9
+ require 'angry_hash'
10
+ else
11
+ $:.unshift root+'lib'
12
+ require root+'lib/angry_hash'
13
+ end
14
+
15
+ require 'rubygems'
16
+ require 'exemplor'
17
+
18
+ class Object
19
+ def tapp(tag=nil)
20
+ print "#{tag}=" if tag
21
+ pp self
22
+ self
23
+ end
24
+ end
@@ -0,0 +1,135 @@
1
+ require 'eg_helper'
2
+ require 'yajl'
3
+
4
+ eg.setup do
5
+ @a = AngryHash[
6
+ :b => {
7
+ :c => 'c',
8
+ :d => 'd'
9
+ }
10
+ ]
11
+
12
+ @b = AngryHash[
13
+ :b => {
14
+ :d => 'dd',
15
+ :e => 'e'
16
+ }
17
+ ]
18
+ end
19
+
20
+ def same_obj(a,b)
21
+ a.__id__ == b.__id__
22
+ end
23
+
24
+ eg 'merges' do
25
+ merged = @a.merge(@b)
26
+
27
+ Assert( ! same_obj( merged, @a ) )
28
+ Assert( ! same_obj( merged, @b ) )
29
+
30
+ Assert( ! merged.b.c? )
31
+ Assert( merged.b.d == 'dd' )
32
+ Assert( merged.b.e == 'e' )
33
+ end
34
+
35
+ eg 'merge dups' do
36
+ a = AngryHash[
37
+ :a => {:b => "cows"}
38
+ ]
39
+ b = AngryHash[
40
+ :a => {:c => "bows"}
41
+ ]
42
+
43
+ merged = a.merge(b)
44
+
45
+ Assert( ! same_obj( merged.a.b, a.a.b ) )
46
+ Assert( same_obj( merged.a.c, b.a.c ) )
47
+ end
48
+
49
+ eg 'updates' do
50
+ merged = @a.update(@b)
51
+
52
+ Assert( same_obj( merged, @a ) )
53
+ Assert( ! same_obj( merged, @b ) )
54
+
55
+ Assert( ! merged.b.c? )
56
+ Assert( merged.b.d == 'dd' )
57
+ Assert( merged.b.e == 'e' )
58
+ end
59
+
60
+ eg 'deep_merge' do
61
+ merged = @a.deep_merge(@b)
62
+
63
+ Show(merged)
64
+
65
+ Assert( ! same_obj( merged, @a ) )
66
+ Assert( ! same_obj( merged, @b ) )
67
+
68
+ Assert( merged.b.c == 'c')
69
+ Assert( merged.b.d == 'dd')
70
+ Assert( merged.b.e == 'e')
71
+ end
72
+
73
+ eg 'deep_update' do
74
+ rv = @a.deep_update(@b)
75
+
76
+ Show(@a)
77
+ Assert( same_obj( rv, @a ) )
78
+ Assert( ! same_obj( @a, @b ) )
79
+
80
+ Assert( ! rv.nil? )
81
+ Assert( @a.b.c == 'c')
82
+ Assert( @a.b.d == 'dd')
83
+ Assert( @a.b.e == 'e')
84
+ end
85
+
86
+ eg 'reverse_deep_merge' do
87
+ merged = @a.reverse_deep_merge(@b)
88
+
89
+ Show(merged)
90
+ Assert( ! merged.nil? )
91
+ Assert( ! same_obj( merged, @a ) )
92
+ Assert( ! same_obj( merged, @b ) )
93
+
94
+ Assert( merged.b.c == 'c')
95
+ Assert( merged.b.d == 'd')
96
+ Assert( merged.b.e == 'e')
97
+ end
98
+
99
+ eg 'deep regression' do
100
+ provider = AngryHash[
101
+ :network => {
102
+ :public => {
103
+ :gateway => '69.164.204.1',
104
+ :netmask => '255.255.255.0'
105
+ },
106
+ :private => {
107
+ :netmask => '255.255.128.0'
108
+ }
109
+ }]
110
+
111
+ server = AngryHash[
112
+ :public_ip => '72.14.191.135',
113
+ :private_ip => '192.168.146.105',
114
+ :network => {
115
+ :public => {:gateway => '72.14.191.1'}
116
+ }]
117
+
118
+ server.provider = provider
119
+ server.network!.reverse_deep_merge!(server.provider.network || {})
120
+
121
+ Show( Yajl::Encoder.encode( server ) )
122
+ end
123
+
124
+ eg 'merge with symbol key' do
125
+ orig = AngryHash[{
126
+ "hosts_db"=>:db,
127
+ "run_list"=>["role[database]"],
128
+ "provider"=>"octopus"
129
+ }]
130
+
131
+ merged = orig.merge(:key=>"db")
132
+
133
+ Show( merged )
134
+ Assert( merged.keys[1].is_a?(String) )
135
+ end
@@ -0,0 +1,215 @@
1
+
2
+ class AngryHash < Hash
3
+ require 'angry_hash/dsl'
4
+ include AngryHash::DSL
5
+
6
+ def self.[](other)
7
+ super(__convert(other))
8
+ end
9
+
10
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
11
+ alias_method :regular_reader, :[] unless method_defined?(:regular_reader)
12
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
13
+
14
+ def []=(key, value)
15
+ regular_writer(__convert_key(key), self.class.__convert_value_without_dup(value))
16
+ end
17
+
18
+ def [](key)
19
+ regular_reader(__convert_key(key))
20
+ end
21
+
22
+ def id
23
+ regular_reader('id')
24
+ end
25
+
26
+ def dup_and_store(key,value)
27
+ regular_writer(__convert_key(key), self.class.__convert_value(value))
28
+ end
29
+
30
+ alias_method :regular_merge, :merge unless method_defined?(:regular_merge)
31
+ def merge(hash)
32
+ regular_merge(self.class.__convert_without_dup(hash))
33
+ end
34
+
35
+ def merge!(other_hash)
36
+ other_hash.each_pair { |key, value| dup_and_store(key,value) }
37
+ self
38
+ end
39
+ alias_method :update, :merge!
40
+
41
+ def dup
42
+ self.class[ self ]
43
+ end
44
+
45
+ def deep_merge(other_hash)
46
+ # XXX this should convert other to AHash!
47
+ self.regular_merge( other_hash ) do |key, oldval, newval|
48
+ oldval = AngryHash.__convert_value(oldval)
49
+ newval = AngryHash.__convert_value(newval)
50
+
51
+ AngryHash === oldval && AngryHash === newval ? oldval.deep_merge(newval) : newval
52
+ end
53
+ end
54
+
55
+ def deep_merge!(other_hash)
56
+ replace(deep_merge(other_hash))
57
+ self
58
+ end
59
+ alias_method :deep_update, :deep_merge!
60
+
61
+ def reverse_deep_merge(other_hash)
62
+ self.class.__convert_value(other_hash).deep_merge(self)
63
+ end
64
+
65
+ def reverse_deep_merge!(other_hash)
66
+ replace(reverse_deep_merge(other_hash))
67
+ self
68
+ end
69
+ alias_method :reverse_deep_update, :reverse_deep_merge!
70
+
71
+
72
+
73
+ def key?(key)
74
+ super(__convert_key(key))
75
+ end
76
+
77
+ alias_method :include?, :key?
78
+ alias_method :has_key?, :key?
79
+ alias_method :member?, :key?
80
+
81
+ def fetch(key, *extras)
82
+ super(__convert_key(key), *extras)
83
+ end
84
+ def values_at(*indices)
85
+ indices.collect {|key| self[__convert_key(key)]}
86
+ end
87
+
88
+ def delete(key)
89
+ super __convert_key(key)
90
+ end
91
+
92
+ def to_hash
93
+ self
94
+ end
95
+
96
+ def to_normal_hash
97
+ __to_hash(self)
98
+ end
99
+ def __to_hash(value,cycle_guard={})
100
+ return cycle_guard[value.hash] if cycle_guard.key?(value.hash)
101
+
102
+ case value
103
+ when Hash
104
+ new_hash = cycle_guard[value.hash] = {}
105
+
106
+ value.inject(new_hash) do |hash,(k,v)|
107
+ hash[k] = __to_hash(v,cycle_guard)
108
+ hash
109
+ end
110
+ when Array
111
+ new_array = cycle_guard[value.hash] = []
112
+
113
+ value.each {|v| new_array << __to_hash(v,cycle_guard)}
114
+ else
115
+ value
116
+ end
117
+ end
118
+
119
+
120
+ def method_missing(method,*args,&blk)
121
+ method_s = method.to_s
122
+
123
+ key = method_s[0..-2]
124
+
125
+ case method_s[-1]
126
+ when ?=
127
+ return super unless args.size == 1 && !block_given?
128
+ self[ key ] = args.first
129
+
130
+ when ??
131
+ return super unless args.empty? && !block_given?
132
+ !! self[key]
133
+
134
+ when ?!
135
+ return super unless args.empty?
136
+ self[key] = AngryHash.new unless self.key?(key)
137
+ self[key]
138
+
139
+ else
140
+ return super unless args.empty? && !block_given?
141
+ self[method_s]
142
+ end
143
+ end
144
+
145
+ def __convert_key(key)
146
+ Symbol === key ? key.to_s : key
147
+ end
148
+ def self.__convert_key(key)
149
+ Symbol === key ? key.to_s : key
150
+ end
151
+
152
+
153
+ # non-duplicating convert
154
+ def self.__convert_without_dup(hash)
155
+ hash.inject(AngryHash.new) do |newhash,(k,v)|
156
+ newhash[__convert_key(k)] = __convert_value_without_dup(v)
157
+ newhash
158
+ end
159
+ end
160
+
161
+ def self.__convert_value_without_dup(v)
162
+ v = v.to_hash if v.respond_to?(:to_hash)
163
+
164
+ case v
165
+ when AngryHash
166
+ v
167
+ when Hash
168
+ __convert_without_dup(v)
169
+ when Array
170
+ v.map {|vv| __convert_value_without_dup(vv)}
171
+ else
172
+ v
173
+ end
174
+ end
175
+
176
+
177
+ # duplicating convert
178
+ def self.__convert(hash,cycle_watch=[])
179
+ new_hash = hash.inject(AngryHash.new) do |hash,(k,v)|
180
+ hash.regular_writer( __convert_key(k), __convert_value(v,cycle_watch) )
181
+ hash
182
+ end
183
+
184
+ new_hash
185
+ end
186
+
187
+ def self.__convert_value(v,cycle_watch=[])
188
+ id = v.__id__
189
+
190
+ return if cycle_watch.include? id
191
+
192
+ begin
193
+ cycle_watch << id
194
+
195
+ original_v = v
196
+ v = v.to_hash if v.respond_to?(:to_hash)
197
+
198
+ case v
199
+ when Hash
200
+ __convert(v,cycle_watch)
201
+ when Array
202
+ v.map {|vv| __convert_value(vv,cycle_watch)}
203
+ when Fixnum,Symbol,NilClass,TrueClass,FalseClass,Float
204
+ v
205
+ else
206
+ v.dup
207
+ end
208
+ ensure
209
+ cycle_watch.pop
210
+ end
211
+ end
212
+
213
+ end
214
+
215
+