attribute_struct 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: