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 +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:
|