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 +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +16 -0
- data/README.md +52 -0
- data/attribute_struct.gemspec +14 -0
- data/lib/attribute_struct/attribute_hash.rb +9 -0
- data/lib/attribute_struct/attribute_struct.rb +193 -0
- data/lib/attribute_struct/monkey_camels.rb +59 -0
- data/lib/attribute_struct/version.rb +6 -0
- data/lib/attribute_struct.rb +2 -0
- metadata +71 -0
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
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,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
|
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:
|