attribute_struct 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ ## v0.1.0
2
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ attribute_struct (0.1.0)
5
+ hashie (~> 2.0.5)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ hashie (2.0.5)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ attribute_struct!
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ ## AttributeStruct
2
+
3
+ This is a helper library that essentially builds hashes. It
4
+ wraps hash building with a nice DSL to make it slightly cleaner,
5
+ more robust, and provide extra features.
6
+
7
+ ### Usage
8
+
9
+ ```ruby
10
+ require 'attribute_struct'
11
+
12
+ struct = AttributeStruct.new
13
+ struct.settings do
14
+ ui.admin do
15
+ enabled true
16
+ port 8080
17
+ bind '*'
18
+ end
19
+ ui.public do
20
+ enabled true
21
+ port 80
22
+ bind '*'
23
+ end
24
+ client('general') do
25
+ enabled false
26
+ end
27
+ end
28
+ ```
29
+
30
+ Now we have an attribute structure that we can
31
+ query and modify. To force it to a hash, we
32
+ can simply dump it:
33
+
34
+ ```ruby
35
+ require 'pp'
36
+
37
+ pp struct._dump
38
+ ```
39
+
40
+ which gives:
41
+
42
+ ```ruby
43
+ {"settings"=>
44
+ {"ui"=>
45
+ {"admin"=>{"enabled"=>true, "port"=>8080, "bind"=>"*"},
46
+ "public"=>{"enabled"=>true, "port"=>80, "bind"=>"*"}},
47
+ "client"=>{"general"=>{"enabled"=>false}}}}
48
+ ```
49
+
50
+ ## Information
51
+
52
+ * Repo: https://github.com/chrisroberts/attribute_struct
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) + '/lib/'
2
+ require 'attribute_struct/version'
3
+ Gem::Specification.new do |s|
4
+ s.name = 'attribute_struct'
5
+ s.version = AttributeStruct::VERSION.version
6
+ s.summary = 'Attribute structures'
7
+ s.author = 'Chris Roberts'
8
+ s.email = 'chrisroberts.code@gmail.com'
9
+ s.homepage = 'http://github.com/chrisroberts/attribute_struct'
10
+ s.description = 'Attribute structures'
11
+ s.require_path = 'lib'
12
+ s.add_dependency 'hashie', '~> 2.0.5'
13
+ s.files = Dir['**/*']
14
+ end
@@ -0,0 +1,9 @@
1
+ require 'hashie/extensions/deep_merge'
2
+ require 'hashie/extensions/indifferent_access'
3
+
4
+ class AttributeStruct
5
+ class AttributeHash < Hash
6
+ include Hashie::Extensions::DeepMerge
7
+ include Hashie::Extensions::IndifferentAccess
8
+ end
9
+ end
@@ -0,0 +1,193 @@
1
+ class AttributeStruct
2
+
3
+ class << self
4
+
5
+ attr_reader :camel_keys
6
+ attr_accessor :force_chef
7
+
8
+ def camel_keys=(val)
9
+ load_the_camels if val
10
+ @camel_keys = !!val
11
+ end
12
+
13
+ def load_the_camels
14
+ unless(@camels_loaded)
15
+ require 'attrubute_struct/monkey_camels'
16
+ @camels_loaded = true
17
+ end
18
+ end
19
+
20
+ def load_the_hash
21
+ unless(@hash_loaded)
22
+ if(defined?(Chef) || force_chef)
23
+ require 'chef/mash'
24
+ require 'chef/mixin/deep_merge'
25
+ else
26
+ require 'attribute_struct/attribute_hash'
27
+ end
28
+ @hash_loaded
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ attr_reader :_camel_keys
35
+
36
+ def initialize(*args, &block)
37
+ self.class.load_the_hash
38
+ @_camel_keys = self.class.camel_keys
39
+ @table = __hashish.new
40
+ unless(args.empty?)
41
+ if(args.size == 1 && args.first.is_a?(Hash))
42
+ _load(args.first)
43
+ end
44
+ end
45
+ end
46
+
47
+ def _camel_keys=(val)
48
+ self.class.load_the_camels if val
49
+ @_camel_keys = !!val
50
+ end
51
+
52
+ def [](key)
53
+ _data[_process_key(key)]
54
+ end
55
+
56
+ def _set(key, val=nil, &block)
57
+ if(val)
58
+ self.method_missing(key, val, &block)
59
+ else
60
+ self.method_missing(key, &block)
61
+ end
62
+ end
63
+
64
+ def method_missing(sym, *args, &block)
65
+ if((s = sym.to_s).end_with?('='))
66
+ s.slice!(-1, s.length)
67
+ sym = s
68
+ end
69
+ sym = _process_key(sym)
70
+ @table[sym] ||= AttributeStruct.new
71
+ if(!args.empty? || block)
72
+ if(args.empty? && block)
73
+ base = @table[sym]
74
+ if(block.arity == 0)
75
+ base.instance_exec(&block)
76
+ else
77
+ base.instance_exec(base, &block)
78
+ end
79
+ @table[sym] = base
80
+ elsif(!args.empty? && block)
81
+ base = @table[sym]
82
+ base = self.class.new unless base.is_a?(self.class)
83
+ @table[sym] = base
84
+ leaf = base
85
+ args.each do |arg|
86
+ leaf = base[arg]
87
+ unless(leaf.is_a?(self.class))
88
+ leaf = self.class.new
89
+ base._set(arg, leaf)
90
+ base = leaf
91
+ end
92
+ end
93
+ if(block.arity == 0)
94
+ leaf.instance_exec(&block)
95
+ else
96
+ leaf.instance_exec(leaf, &block)
97
+ end
98
+ else
99
+ @table[sym] = args.first
100
+ end
101
+ end
102
+ @table[sym]
103
+ end
104
+
105
+ def nil?
106
+ _data.empty?
107
+ end
108
+
109
+ def _keys
110
+ _data.keys
111
+ end
112
+
113
+ def _data
114
+ @table
115
+ end
116
+
117
+ def _dump
118
+ __hashish[
119
+ *(@table.map{|key, value|
120
+ [key, value.is_a?(self.class) ? value._dump : value]
121
+ }.flatten(1))
122
+ ]
123
+ end
124
+
125
+ def _load(hashish)
126
+ @table.clear
127
+ hashish.each do |key, value|
128
+ if(value.is_a?(Hash))
129
+ self._set(key)._load(value)
130
+ else
131
+ self._set(key, value)
132
+ end
133
+ end
134
+ self
135
+ end
136
+
137
+ def _merge(target)
138
+ source = deep_copy
139
+ dest = target.deep_copy
140
+ if(defined?(Mash))
141
+ result = Chef::Mixin::DeepMerge.merge(source, dest)
142
+ else
143
+ result = source.deep_merge(dest)
144
+ end
145
+ AttributeStruct.new(result)
146
+ end
147
+
148
+ def _merge!(target)
149
+ result = _merge(target)._dump
150
+ _load(result)
151
+ self
152
+ end
153
+
154
+ def __hashish
155
+ defined?(Mash) ? Mash : AttributeHash
156
+ end
157
+
158
+ def do_dup(v)
159
+ begin
160
+ v.dup
161
+ rescue
162
+ v.is_a?(Symbol) ? v.to_s : v
163
+ end
164
+ end
165
+
166
+ def deep_copy(thing=nil)
167
+ thing ||= _dump
168
+ if(thing.is_a?(Enumerable))
169
+ val = thing.map{|v| v.is_a?(Enumerable) ? deep_copy(v) : do_dup(v) }
170
+ else
171
+ val = do_dup(thing)
172
+ end
173
+ if(thing.is_a?(Hash))
174
+ val = __hashish[*val.flatten(1)]
175
+ end
176
+ val
177
+ end
178
+
179
+ def _process_key(key)
180
+ key = key.to_s
181
+ if(_camel_keys && key._camel?)
182
+ key.to_s.split('_').map do |part|
183
+ "#{part[0,1].upcase}#{part[1,part.size]}"
184
+ end.join.to_sym
185
+ else
186
+ if(_camel_keys)
187
+ # Convert so Hash doesn't make a new one and lose the meta
188
+ key = CamelString.new(key) unless key.is_a?(CamelString)
189
+ end
190
+ key
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,59 @@
1
+ module MonkeyCamels
2
+
3
+ class << self
4
+ def included(klass)
5
+ klass.class_eval do
6
+
7
+ include Humps
8
+
9
+ alias_method :un_camel_to_s, :to_s
10
+ alias_method :to_s, :camel_to_s
11
+ alias_method :un_camel_initialize_copy, :initialize_copy
12
+ alias_method :initialize_copy, :camel_initialize_copy
13
+ end
14
+ end
15
+ end
16
+
17
+ def camel_initialize_copy(orig)
18
+ new_val = un_camel_initialize_copy(orig)
19
+ orig._camel? ? new_val : new_val._no_hump
20
+ end
21
+
22
+ def camel_to_s
23
+ val = un_camel_to_s
24
+ _camel? ? val : val._no_hump
25
+ end
26
+
27
+ module Humps
28
+
29
+ def _camel?
30
+ !@__not_camel
31
+ end
32
+
33
+ def _no_hump
34
+ @__not_camel = true
35
+ self
36
+ end
37
+
38
+ def _hump
39
+ @__not_camel = false
40
+ self
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ # Force some monkeys around
48
+ String.send(:include, MonkeyCamels)
49
+ Symbol.send(:include, MonkeyCamels)
50
+
51
+ # Specialized type
52
+ class CamelString < String
53
+ def initialize(val=nil)
54
+ super
55
+ if(val.respond_to?(:_camel?))
56
+ _no_hump unless val._camel?
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,6 @@
1
+ class AttributeStruct
2
+ class Version < Gem::Version
3
+ end
4
+
5
+ VERSION = Version.new('0.1.0')
6
+ end
@@ -0,0 +1,2 @@
1
+ require 'attribute_struct/version'
2
+ require 'attribute_struct/attribute_struct'
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attribute_struct
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Roberts
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hashie
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.5
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.0.5
30
+ description: Attribute structures
31
+ email: chrisroberts.code@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - lib/attribute_struct.rb
37
+ - lib/attribute_struct/attribute_struct.rb
38
+ - lib/attribute_struct/version.rb
39
+ - lib/attribute_struct/attribute_hash.rb
40
+ - lib/attribute_struct/monkey_camels.rb
41
+ - Gemfile
42
+ - README.md
43
+ - attribute_struct.gemspec
44
+ - CHANGELOG.md
45
+ - Gemfile.lock
46
+ homepage: http://github.com/chrisroberts/attribute_struct
47
+ licenses: []
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 1.8.24
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Attribute structures
70
+ test_files: []
71
+ has_rdoc: