blobject 0.3.7 → 0.4.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.
- checksums.yaml +7 -0
- data/.gitignore +0 -0
- data/.pryrc +4 -7
- data/.yardopts +2 -0
- data/Gemfile +0 -0
- data/Gemfile.lock +17 -23
- data/README.markdown +64 -4
- data/Rakefile +0 -0
- data/assets/blob_defn.png +0 -0
- data/assets/blobject.png +0 -0
- data/benchmarks/results +0 -0
- data/blobject.gemspec +3 -3
- data/blobject.psd +0 -0
- data/doc/Blobject.html +242 -137
- data/doc/_index.html +1 -1
- data/doc/class_list.html +0 -0
- data/doc/css/common.css +0 -0
- data/doc/css/full_list.css +0 -0
- data/doc/css/style.css +0 -0
- data/doc/file.README.html +103 -18
- data/doc/file_list.html +0 -0
- data/doc/frames.html +0 -0
- data/doc/index.html +103 -18
- data/doc/js/app.js +0 -0
- data/doc/js/full_list.js +0 -0
- data/doc/js/jquery.js +0 -0
- data/doc/method_list.html +16 -0
- data/doc/top-level-namespace.html +1 -1
- data/lib/blobject.rb +46 -57
- data/lib/blobject/version.rb +2 -1
- data/makefile +15 -1
- data/spec/blobject_spec.rb +29 -27
- data/spec/env.rb +4 -3
- data/spec/sample_data/sample.json +0 -0
- data/spec/sample_data/sample.yaml +0 -0
- data/spec/sample_data/sample2.json +0 -0
- data/spec/sample_data/sample2.yaml +0 -0
- data/spec/sample_data/sample3.json +25 -0
- data/try_blobject.sh +4 -0
- metadata +42 -29
data/doc/_index.html
CHANGED
@@ -101,7 +101,7 @@
|
|
101
101
|
</div>
|
102
102
|
|
103
103
|
<div id="footer">
|
104
|
-
Generated on
|
104
|
+
Generated on Sun Jun 17 00:20:42 2012 by
|
105
105
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
106
106
|
0.8.1 (ruby-1.9.3).
|
107
107
|
</div>
|
data/doc/class_list.html
CHANGED
File without changes
|
data/doc/css/common.css
CHANGED
File without changes
|
data/doc/css/full_list.css
CHANGED
File without changes
|
data/doc/css/style.css
CHANGED
File without changes
|
data/doc/file.README.html
CHANGED
@@ -61,22 +61,54 @@
|
|
61
61
|
|
62
62
|
<iframe id="search_frame"></iframe>
|
63
63
|
|
64
|
-
<div id="content"><div id='filecontents'><p><img src="https://github.com/sjltaylor/blobject/raw/master/blobject.png" alt="">
|
65
|
-
<img src="https://github.com/sjltaylor/blobject/raw/master/blob_defn.png" alt=""></p>
|
64
|
+
<div id="content"><div id='filecontents'><p><img src="https://github.com/sjltaylor/blobject/raw/master/assets/blobject.png" alt=""> </p>
|
66
65
|
|
67
|
-
<
|
68
|
-
|
66
|
+
<p>Rdocs: <a href="http://sjltaylor.github.com/blobject">http://sjltaylor.github.com/blobject</a></p>
|
67
|
+
|
68
|
+
<h2>About</h2>
|
69
|
+
|
70
|
+
<p>Consider the following json sample...</p>
|
71
|
+
|
72
|
+
<pre class="code ruby"><code>{
|
73
|
+
"device_id": 63354,
|
74
|
+
"channel_no": 6,
|
75
|
+
"interval_ms": 15000,
|
76
|
+
"readings": [
|
77
|
+
{
|
78
|
+
"value": 14232,
|
79
|
+
"time": 1339880802
|
80
|
+
},
|
81
|
+
{
|
82
|
+
"value": 14232,
|
83
|
+
"time": 1339880817
|
84
|
+
}
|
85
|
+
],
|
86
|
+
"calibration": {
|
87
|
+
"staff": {
|
88
|
+
"name": {
|
89
|
+
"first": "Carl",
|
90
|
+
"middle_initial": "I",
|
91
|
+
"second": "Brator"
|
92
|
+
}
|
93
|
+
},
|
94
|
+
"last_calibration": "2010-06-16T22:06:42+01:00"
|
95
|
+
}
|
96
|
+
}
|
69
97
|
</code></pre>
|
70
98
|
|
71
|
-
<
|
99
|
+
<p>Blobject let's you do this (complete code listing, no predefined data structures):</p>
|
72
100
|
|
73
|
-
<
|
101
|
+
<pre class="code ruby"><code>data = Blobject.from_json HTTParty.get('https://raw.github.com/sjltaylor/blobject/master/spec/sample_data/sample3.json')
|
74
102
|
|
75
|
-
|
103
|
+
full_name = "#{data.calibration.staff.name.first}#{data.calibration.staff.name.middle_initial}#{data.calibration.staff.name.second}".capitalize
|
104
|
+
=> "Calibrator"
|
76
105
|
|
77
|
-
|
106
|
+
last_reading = data.readings.last.value if data.readings?
|
107
|
+
=> 14232
|
108
|
+
</code></pre>
|
78
109
|
|
79
|
-
<p>
|
110
|
+
<p>Blobject is convenient to creating json payloads too.
|
111
|
+
Blobjects are <em>freeform</em> which means you can do this...</p>
|
80
112
|
|
81
113
|
<pre class="code ruby"><code><span class='id identifier rubyid_data'>data</span> <span class='op'>=</span> <span class='const'>Blobject</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span>
|
82
114
|
|
@@ -84,24 +116,30 @@ class Blobject
|
|
84
116
|
<span class='id identifier rubyid_data'>data</span><span class='period'>.</span><span class='id identifier rubyid_number'>number</span> <span class='op'>=</span> <span class='int'>316</span>
|
85
117
|
</code></pre>
|
86
118
|
|
87
|
-
<p>like an OpenStruct
|
119
|
+
<p>like an <code>OpenStruct</code>, the members are not predefined attributes</p>
|
88
120
|
|
89
|
-
<p>unlike OpenStruct
|
121
|
+
<p>unlike <code>OpenStruct</code>, <code>Blobject</code>s can be arbitrarily <em>complex</em> which means you can do this...</p>
|
90
122
|
|
91
|
-
<pre class="code ruby"><code
|
123
|
+
<pre class="code ruby"><code>data = Blobject.new
|
124
|
+
=> {}
|
92
125
|
|
93
|
-
|
94
|
-
|
126
|
+
data.name.first = "Johnny"
|
127
|
+
data.name.surname = "Begood"
|
128
|
+
=> {:name=>{:first=>"Johnny", :surname=>"Begood"}}
|
95
129
|
|
96
|
-
|
130
|
+
data.my.object.with.deep.nested.members = "happy place"
|
131
|
+
=> {:name=>{:first=>"Johnny", :surname=>"Begood"}, :my=>{:object=>{:with=>{:deep=>{:nested=>{:members=>"happy place"}}}}}}
|
97
132
|
</code></pre>
|
98
133
|
|
99
|
-
<p>
|
134
|
+
<p>You can assign hashes which become nested blobjects</p>
|
100
135
|
|
101
136
|
<p>data.details = { code: 41239, ref: "#22322" }</p>
|
102
137
|
|
103
138
|
<p>data.details.code
|
104
139
|
=> 41239
|
140
|
+
data.details.code = 11322
|
141
|
+
data.details.code
|
142
|
+
=> 11322
|
105
143
|
data.details.ref
|
106
144
|
=> "#22322"</p>
|
107
145
|
|
@@ -109,8 +147,53 @@ class Blobject
|
|
109
147
|
|
110
148
|
<pre class="code ruby"><code>data.something_here?
|
111
149
|
=> false
|
150
|
+
data.name?
|
151
|
+
=> true
|
152
|
+
</code></pre>
|
153
|
+
|
154
|
+
<p>You can use it like a hash</p>
|
155
|
+
|
156
|
+
<pre class="code ruby"><code>data[:name]
|
157
|
+
=> {:first=>"Johnny", :surname=>"Begood"}
|
158
|
+
|
159
|
+
data[:name][:first] = "Jimmy"; data[:name]
|
160
|
+
=> {:first=>"Jimmy", :surname=>"Begood"}
|
161
|
+
|
162
|
+
data.empty?
|
163
|
+
=> false
|
164
|
+
|
165
|
+
data.name == {:first=>"Jimmy", :surname=>"Begood"}
|
166
|
+
=> true
|
112
167
|
</code></pre>
|
113
168
|
|
169
|
+
<p>You can get access to the internal hash with <code>Blobject#hash</code> or a de-blobjectified copy with <code>Blobject#to_hash</code></p>
|
170
|
+
|
171
|
+
<p>You can call <code>Blobject#freeze</code> to prevent the data being modified. This still allows chained calls: <code>blobject.data.nested.is_something_here?</code> but assignments will raise <code>RuntimeError: can't modify frozen Hash</code></p>
|
172
|
+
|
173
|
+
<p>You can work with JSON data using <code>Blobject.from_json</code> and <code>Blobject#to_json</code>, in Rails, you can use <code>Blobject#as_json</code> as you would with a hash.</p>
|
174
|
+
|
175
|
+
<p>You can work with YAML data using <code>Blobject.from_yaml</code> and <code>Blobject#to_yaml</code>.</p>
|
176
|
+
|
177
|
+
<h2>Try it out...</h2>
|
178
|
+
|
179
|
+
<ol>
|
180
|
+
<li>Install the gem (ruby 1.9.2+ required): <code>sh <(curl https://raw.github.com/sjltaylor/blobject/master/try_blobject.sh)</code></li>
|
181
|
+
<li>Load data from an api...
|
182
|
+
payload = Blobject.from<em>json HTTParty.get('<a href="https://raw.github.com/sjltaylor/blobject/master/spec/sample">https://raw.github.com/sjltaylor/blobject/master/spec/sample</a></em>data/sample3.json')</li>
|
183
|
+
<li>Inspect it
|
184
|
+
payload.calibration.staff.name
|
185
|
+
=> :middle_initial=>"I", :second=>"Brator"</li>
|
186
|
+
<li>Test for optional data members
|
187
|
+
payload.channel<em>no?
|
188
|
+
=> true
|
189
|
+
payload.something</em>that<em>is</em>not_there?
|
190
|
+
=> false</li>
|
191
|
+
<li>Draw your own payload
|
192
|
+
mine = Blobject.new my: 123
|
193
|
+
mine.to_json
|
194
|
+
=> "\"my\":{\"data\":123}"</li>
|
195
|
+
</ol>
|
196
|
+
|
114
197
|
<h2>Used for Configuration</h2>
|
115
198
|
|
116
199
|
<p>Consider a configuration object which contains credentials for a third-party api.</p>
|
@@ -150,7 +233,7 @@ class Blobject
|
|
150
233
|
<span class='kw'>end</span>
|
151
234
|
</code></pre>
|
152
235
|
|
153
|
-
<h2>
|
236
|
+
<h2>Serialization</h2>
|
154
237
|
|
155
238
|
<p>Blobjects can be used to easily build complex payloads.</p>
|
156
239
|
|
@@ -257,10 +340,12 @@ Hashie: 1.880000 0.000000 1.880000 ( 1.921718)
|
|
257
340
|
|
258
341
|
<p>Copyright (c) 2012 Sam Taylor. See LICENSE.txt for
|
259
342
|
further details.</p>
|
343
|
+
|
344
|
+
<p><img src="https://github.com/sjltaylor/blobject/raw/master/assets/blob_defn.png" alt=""></p>
|
260
345
|
</div></div>
|
261
346
|
|
262
347
|
<div id="footer">
|
263
|
-
Generated on
|
348
|
+
Generated on Sun Jun 17 00:20:42 2012 by
|
264
349
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
265
350
|
0.8.1 (ruby-1.9.3).
|
266
351
|
</div>
|
data/doc/file_list.html
CHANGED
File without changes
|
data/doc/frames.html
CHANGED
File without changes
|
data/doc/index.html
CHANGED
@@ -61,22 +61,54 @@
|
|
61
61
|
|
62
62
|
<iframe id="search_frame"></iframe>
|
63
63
|
|
64
|
-
<div id="content"><div id='filecontents'><p><img src="https://github.com/sjltaylor/blobject/raw/master/blobject.png" alt="">
|
65
|
-
<img src="https://github.com/sjltaylor/blobject/raw/master/blob_defn.png" alt=""></p>
|
64
|
+
<div id="content"><div id='filecontents'><p><img src="https://github.com/sjltaylor/blobject/raw/master/assets/blobject.png" alt=""> </p>
|
66
65
|
|
67
|
-
<
|
68
|
-
|
66
|
+
<p>Rdocs: <a href="http://sjltaylor.github.com/blobject">http://sjltaylor.github.com/blobject</a></p>
|
67
|
+
|
68
|
+
<h2>About</h2>
|
69
|
+
|
70
|
+
<p>Consider the following json sample...</p>
|
71
|
+
|
72
|
+
<pre class="code ruby"><code>{
|
73
|
+
"device_id": 63354,
|
74
|
+
"channel_no": 6,
|
75
|
+
"interval_ms": 15000,
|
76
|
+
"readings": [
|
77
|
+
{
|
78
|
+
"value": 14232,
|
79
|
+
"time": 1339880802
|
80
|
+
},
|
81
|
+
{
|
82
|
+
"value": 14232,
|
83
|
+
"time": 1339880817
|
84
|
+
}
|
85
|
+
],
|
86
|
+
"calibration": {
|
87
|
+
"staff": {
|
88
|
+
"name": {
|
89
|
+
"first": "Carl",
|
90
|
+
"middle_initial": "I",
|
91
|
+
"second": "Brator"
|
92
|
+
}
|
93
|
+
},
|
94
|
+
"last_calibration": "2010-06-16T22:06:42+01:00"
|
95
|
+
}
|
96
|
+
}
|
69
97
|
</code></pre>
|
70
98
|
|
71
|
-
<
|
99
|
+
<p>Blobject let's you do this (complete code listing, no predefined data structures):</p>
|
72
100
|
|
73
|
-
<
|
101
|
+
<pre class="code ruby"><code>data = Blobject.from_json HTTParty.get('https://raw.github.com/sjltaylor/blobject/master/spec/sample_data/sample3.json')
|
74
102
|
|
75
|
-
|
103
|
+
full_name = "#{data.calibration.staff.name.first}#{data.calibration.staff.name.middle_initial}#{data.calibration.staff.name.second}".capitalize
|
104
|
+
=> "Calibrator"
|
76
105
|
|
77
|
-
|
106
|
+
last_reading = data.readings.last.value if data.readings?
|
107
|
+
=> 14232
|
108
|
+
</code></pre>
|
78
109
|
|
79
|
-
<p>
|
110
|
+
<p>Blobject is convenient to creating json payloads too.
|
111
|
+
Blobjects are <em>freeform</em> which means you can do this...</p>
|
80
112
|
|
81
113
|
<pre class="code ruby"><code><span class='id identifier rubyid_data'>data</span> <span class='op'>=</span> <span class='const'>Blobject</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span>
|
82
114
|
|
@@ -84,24 +116,30 @@ class Blobject
|
|
84
116
|
<span class='id identifier rubyid_data'>data</span><span class='period'>.</span><span class='id identifier rubyid_number'>number</span> <span class='op'>=</span> <span class='int'>316</span>
|
85
117
|
</code></pre>
|
86
118
|
|
87
|
-
<p>like an OpenStruct
|
119
|
+
<p>like an <code>OpenStruct</code>, the members are not predefined attributes</p>
|
88
120
|
|
89
|
-
<p>unlike OpenStruct
|
121
|
+
<p>unlike <code>OpenStruct</code>, <code>Blobject</code>s can be arbitrarily <em>complex</em> which means you can do this...</p>
|
90
122
|
|
91
|
-
<pre class="code ruby"><code
|
123
|
+
<pre class="code ruby"><code>data = Blobject.new
|
124
|
+
=> {}
|
92
125
|
|
93
|
-
|
94
|
-
|
126
|
+
data.name.first = "Johnny"
|
127
|
+
data.name.surname = "Begood"
|
128
|
+
=> {:name=>{:first=>"Johnny", :surname=>"Begood"}}
|
95
129
|
|
96
|
-
|
130
|
+
data.my.object.with.deep.nested.members = "happy place"
|
131
|
+
=> {:name=>{:first=>"Johnny", :surname=>"Begood"}, :my=>{:object=>{:with=>{:deep=>{:nested=>{:members=>"happy place"}}}}}}
|
97
132
|
</code></pre>
|
98
133
|
|
99
|
-
<p>
|
134
|
+
<p>You can assign hashes which become nested blobjects</p>
|
100
135
|
|
101
136
|
<p>data.details = { code: 41239, ref: "#22322" }</p>
|
102
137
|
|
103
138
|
<p>data.details.code
|
104
139
|
=> 41239
|
140
|
+
data.details.code = 11322
|
141
|
+
data.details.code
|
142
|
+
=> 11322
|
105
143
|
data.details.ref
|
106
144
|
=> "#22322"</p>
|
107
145
|
|
@@ -109,8 +147,53 @@ class Blobject
|
|
109
147
|
|
110
148
|
<pre class="code ruby"><code>data.something_here?
|
111
149
|
=> false
|
150
|
+
data.name?
|
151
|
+
=> true
|
152
|
+
</code></pre>
|
153
|
+
|
154
|
+
<p>You can use it like a hash</p>
|
155
|
+
|
156
|
+
<pre class="code ruby"><code>data[:name]
|
157
|
+
=> {:first=>"Johnny", :surname=>"Begood"}
|
158
|
+
|
159
|
+
data[:name][:first] = "Jimmy"; data[:name]
|
160
|
+
=> {:first=>"Jimmy", :surname=>"Begood"}
|
161
|
+
|
162
|
+
data.empty?
|
163
|
+
=> false
|
164
|
+
|
165
|
+
data.name == {:first=>"Jimmy", :surname=>"Begood"}
|
166
|
+
=> true
|
112
167
|
</code></pre>
|
113
168
|
|
169
|
+
<p>You can get access to the internal hash with <code>Blobject#hash</code> or a de-blobjectified copy with <code>Blobject#to_hash</code></p>
|
170
|
+
|
171
|
+
<p>You can call <code>Blobject#freeze</code> to prevent the data being modified. This still allows chained calls: <code>blobject.data.nested.is_something_here?</code> but assignments will raise <code>RuntimeError: can't modify frozen Hash</code></p>
|
172
|
+
|
173
|
+
<p>You can work with JSON data using <code>Blobject.from_json</code> and <code>Blobject#to_json</code>, in Rails, you can use <code>Blobject#as_json</code> as you would with a hash.</p>
|
174
|
+
|
175
|
+
<p>You can work with YAML data using <code>Blobject.from_yaml</code> and <code>Blobject#to_yaml</code>.</p>
|
176
|
+
|
177
|
+
<h2>Try it out...</h2>
|
178
|
+
|
179
|
+
<ol>
|
180
|
+
<li>Install the gem (ruby 1.9.2+ required): <code>sh <(curl https://raw.github.com/sjltaylor/blobject/master/try_blobject.sh)</code></li>
|
181
|
+
<li>Load data from an api...
|
182
|
+
payload = Blobject.from<em>json HTTParty.get('<a href="https://raw.github.com/sjltaylor/blobject/master/spec/sample">https://raw.github.com/sjltaylor/blobject/master/spec/sample</a></em>data/sample3.json')</li>
|
183
|
+
<li>Inspect it
|
184
|
+
payload.calibration.staff.name
|
185
|
+
=> :middle_initial=>"I", :second=>"Brator"</li>
|
186
|
+
<li>Test for optional data members
|
187
|
+
payload.channel<em>no?
|
188
|
+
=> true
|
189
|
+
payload.something</em>that<em>is</em>not_there?
|
190
|
+
=> false</li>
|
191
|
+
<li>Draw your own payload
|
192
|
+
mine = Blobject.new my: 123
|
193
|
+
mine.to_json
|
194
|
+
=> "\"my\":{\"data\":123}"</li>
|
195
|
+
</ol>
|
196
|
+
|
114
197
|
<h2>Used for Configuration</h2>
|
115
198
|
|
116
199
|
<p>Consider a configuration object which contains credentials for a third-party api.</p>
|
@@ -150,7 +233,7 @@ class Blobject
|
|
150
233
|
<span class='kw'>end</span>
|
151
234
|
</code></pre>
|
152
235
|
|
153
|
-
<h2>
|
236
|
+
<h2>Serialization</h2>
|
154
237
|
|
155
238
|
<p>Blobjects can be used to easily build complex payloads.</p>
|
156
239
|
|
@@ -257,10 +340,12 @@ Hashie: 1.880000 0.000000 1.880000 ( 1.921718)
|
|
257
340
|
|
258
341
|
<p>Copyright (c) 2012 Sam Taylor. See LICENSE.txt for
|
259
342
|
further details.</p>
|
343
|
+
|
344
|
+
<p><img src="https://github.com/sjltaylor/blobject/raw/master/assets/blob_defn.png" alt=""></p>
|
260
345
|
</div></div>
|
261
346
|
|
262
347
|
<div id="footer">
|
263
|
-
Generated on
|
348
|
+
Generated on Sun Jun 17 00:20:42 2012 by
|
264
349
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
265
350
|
0.8.1 (ruby-1.9.3).
|
266
351
|
</div>
|
data/doc/js/app.js
CHANGED
File without changes
|
data/doc/js/full_list.js
CHANGED
File without changes
|
data/doc/js/jquery.js
CHANGED
File without changes
|
data/doc/method_list.html
CHANGED
@@ -79,6 +79,14 @@
|
|
79
79
|
|
80
80
|
|
81
81
|
<li class="r1 ">
|
82
|
+
<span class='object_link'><a href="Blobject.html#empty%3F-instance_method" title="Blobject#empty? (method)">#empty?</a></span>
|
83
|
+
|
84
|
+
<small>Blobject</small>
|
85
|
+
|
86
|
+
</li>
|
87
|
+
|
88
|
+
|
89
|
+
<li class="r2 ">
|
82
90
|
<span class='object_link'><a href="Blobject.html#freeze-instance_method" title="Blobject#freeze (method)">#freeze</a></span>
|
83
91
|
|
84
92
|
<small>Blobject</small>
|
@@ -86,6 +94,14 @@
|
|
86
94
|
</li>
|
87
95
|
|
88
96
|
|
97
|
+
<li class="r1 ">
|
98
|
+
<span class='object_link'><a href="Blobject.html#freeze_r-instance_method" title="Blobject#freeze_r (method)">#freeze_r</a></span>
|
99
|
+
|
100
|
+
<small>Blobject</small>
|
101
|
+
|
102
|
+
</li>
|
103
|
+
|
104
|
+
|
89
105
|
<li class="r2 ">
|
90
106
|
<span class='object_link'><a href="Blobject.html#from_json-class_method" title="Blobject.from_json (method)">from_json</a></span>
|
91
107
|
|
@@ -103,7 +103,7 @@
|
|
103
103
|
</div>
|
104
104
|
|
105
105
|
<div id="footer">
|
106
|
-
Generated on
|
106
|
+
Generated on Sun Jun 17 00:20:42 2012 by
|
107
107
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
108
108
|
0.8.1 (ruby-1.9.3).
|
109
109
|
</div>
|
data/lib/blobject.rb
CHANGED
@@ -4,7 +4,7 @@ require_relative 'blobject/version'
|
|
4
4
|
|
5
5
|
# Wraps a hash to provide arbitrarily nested object-style attribute access
|
6
6
|
class Blobject
|
7
|
-
|
7
|
+
|
8
8
|
# filter :to_ary else Blobject#to_ary returns a
|
9
9
|
# blobject which is not cool, especially if you are puts.
|
10
10
|
ProhibitedNames = [:to_ary]
|
@@ -27,25 +27,25 @@ class Blobject
|
|
27
27
|
yield self if block_given?
|
28
28
|
end
|
29
29
|
|
30
|
+
# indicates whether the blobject contains any data
|
30
31
|
def empty?
|
31
32
|
@hash.empty?
|
32
33
|
end
|
33
34
|
|
34
35
|
# delegates to the internal Hash
|
35
36
|
def inspect
|
36
|
-
|
37
|
+
|
37
38
|
@hash.inspect
|
38
39
|
end
|
39
40
|
|
40
41
|
# access the internal hash. be careful, this is _not_ a copy
|
41
42
|
def hash
|
42
|
-
|
43
43
|
@hash
|
44
44
|
end
|
45
45
|
|
46
46
|
# creates a recursive copy of the internal hash
|
47
47
|
def to_hash
|
48
|
-
|
48
|
+
|
49
49
|
h = hash.dup
|
50
50
|
@hash.each do |name, node|
|
51
51
|
h[name] = node.to_hash if node.respond_to? :to_hash
|
@@ -63,7 +63,7 @@ class Blobject
|
|
63
63
|
# assignment in conditionals is usually a bad smell, here it helps minimize regex matching
|
64
64
|
when (name = method[/^\w+$/, 0]) && params.length == 0
|
65
65
|
# the call is an attribute reader
|
66
|
-
|
66
|
+
|
67
67
|
return self.class.new.freeze if frozen? and not @hash.has_key?(method)
|
68
68
|
self.class.send :__define_attribute__, name
|
69
69
|
|
@@ -99,18 +99,14 @@ class Blobject
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def respond_to? method
|
102
|
-
|
103
|
-
|
104
|
-
return false if ProhibitedNames.include?(method)
|
105
|
-
|
106
|
-
method = method.to_s
|
102
|
+
super || self.__respond_to__?(method)
|
103
|
+
end
|
107
104
|
|
108
|
-
|
109
|
-
|
110
|
-
end
|
105
|
+
def respond_to_missing?(method, *)
|
106
|
+
super || self.__respond_to__?(method)
|
111
107
|
end
|
112
108
|
|
113
|
-
# compares Blobjects to Blobjects or Hashes
|
109
|
+
# compares Blobjects to Blobjects or Hashes for equality
|
114
110
|
def == other
|
115
111
|
return @hash == other.hash if other.class <= Blobject
|
116
112
|
return @hash == other if other.class <= Hash
|
@@ -119,30 +115,23 @@ class Blobject
|
|
119
115
|
|
120
116
|
# hash-like access to the Blobject's attributes
|
121
117
|
def [] name
|
122
|
-
|
118
|
+
|
123
119
|
send name
|
124
120
|
end
|
125
121
|
|
126
|
-
# hash-like
|
122
|
+
# hash-like attribute setter
|
127
123
|
def []= name, value
|
128
|
-
|
124
|
+
|
129
125
|
send "#{name.to_s}=", value
|
130
126
|
end
|
131
|
-
|
127
|
+
|
132
128
|
# freeze a Blobject to prevent it being modified
|
133
129
|
def freeze
|
134
|
-
@hash
|
130
|
+
self.class.send(:__freeze_r__, @hash) unless frozen?
|
135
131
|
super
|
136
132
|
end
|
137
133
|
|
138
|
-
|
139
|
-
self.class.send(:__freeze_r__, self)
|
140
|
-
freeze
|
141
|
-
end
|
142
|
-
|
143
|
-
|
144
|
-
# returns a hash which can be serialized as json.
|
145
|
-
# this is for use in rails controllers: `render json: blobject`
|
134
|
+
# for rails: `render json: blobject`
|
146
135
|
def as_json *args
|
147
136
|
return hash.as_json(*args) if hash.respond_to? :as_json
|
148
137
|
to_hash
|
@@ -155,32 +144,30 @@ class Blobject
|
|
155
144
|
|
156
145
|
# serialize the Blobject as a yaml string
|
157
146
|
def to_yaml
|
158
|
-
|
147
|
+
|
159
148
|
as_yaml.to_yaml
|
160
149
|
end
|
161
150
|
|
162
|
-
# get a Blobject from a json string
|
163
|
-
# if the yaml string describes an array, an array will be returned
|
151
|
+
# get a Blobject from a json string, if the yaml string describes an array, an array will be returned
|
164
152
|
def self.from_json json
|
165
|
-
|
153
|
+
|
166
154
|
__blobjectify__(JSON.parse(json))
|
167
155
|
end
|
168
156
|
|
169
|
-
# get a Blobject from a yaml string
|
170
|
-
# if the yaml string describes an array, an array will be returned
|
157
|
+
# get a Blobject from a yaml string, if the yaml string describes an array, an array will be returned
|
171
158
|
def self.from_yaml yaml
|
172
|
-
|
159
|
+
|
173
160
|
__blobjectify__(YAML.load(yaml))
|
174
161
|
end
|
175
162
|
|
176
|
-
|
177
|
-
# to avoid naming collisions private method names are prefixed and suffix with double unerscores (__)
|
163
|
+
protected
|
164
|
+
# to avoid naming collisions private method names are prefixed and suffix with double unerscores (__)
|
178
165
|
|
179
|
-
# Used to tag and
|
166
|
+
# Used to tag and re-raise errors from a Blobject
|
180
167
|
# Refer to "Tagging exceptions with modules" on p97 in Exceptional Ruby by Avdi Grimm
|
181
168
|
# errors from this library can be handled with rescue Blobject::Error
|
182
169
|
module Error; end
|
183
|
-
|
170
|
+
|
184
171
|
def __tag_and_raise__ e
|
185
172
|
raise e
|
186
173
|
rescue
|
@@ -188,29 +175,31 @@ private
|
|
188
175
|
raise e
|
189
176
|
end
|
190
177
|
|
178
|
+
def __respond_to__?(method)
|
179
|
+
return false if ProhibitedNames.include?(method)
|
180
|
+
|
181
|
+
method = method.to_s
|
182
|
+
|
183
|
+
[/^(\w+)=$/, /^(\w+)\?$/, /^\w+$/].any? do |r|
|
184
|
+
r.match(method)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
191
188
|
class << self
|
192
189
|
|
193
|
-
|
190
|
+
protected
|
194
191
|
|
195
192
|
def __freeze_r__ object
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
e.freeze
|
201
|
-
__freeze_r__(e)
|
202
|
-
end
|
203
|
-
when Hash
|
204
|
-
return object.each do |k, v|
|
193
|
+
|
194
|
+
if object.respond_to?(:each) && object.each.is_a?(Enumerator)
|
195
|
+
values = object.is_a?(Hash) ? object.values : object
|
196
|
+
values.each do |v|
|
205
197
|
v.freeze
|
206
198
|
__freeze_r__(v)
|
207
199
|
end
|
208
|
-
when Blobject
|
209
|
-
object.freeze
|
210
|
-
__freeze_r__ object.hash
|
211
|
-
else
|
212
|
-
object.freeze
|
213
200
|
end
|
201
|
+
|
202
|
+
object.freeze
|
214
203
|
end
|
215
204
|
|
216
205
|
def __blobjectify__ object
|
@@ -236,7 +225,7 @@ private
|
|
236
225
|
begin
|
237
226
|
value = self.class.send(:__blobjectify__, value) if value.is_a?(Hash) or value.is_a?(Array)
|
238
227
|
@hash[name] = value
|
239
|
-
rescue
|
228
|
+
rescue => ex
|
240
229
|
__tag_and_raise__(ex)
|
241
230
|
end
|
242
231
|
@store_in_parent.call unless @store_in_parent.nil?
|
@@ -248,7 +237,7 @@ private
|
|
248
237
|
|
249
238
|
value = @hash[name]
|
250
239
|
|
251
|
-
if value.nil?
|
240
|
+
if value.nil?
|
252
241
|
value = self.class.new
|
253
242
|
@hash[name] = value unless frozen?
|
254
243
|
end
|
@@ -260,11 +249,11 @@ private
|
|
260
249
|
checker_name = (name.to_s + '?').to_sym
|
261
250
|
unless methods.include? checker_name
|
262
251
|
self.send :define_method, checker_name do
|
263
|
-
@hash
|
252
|
+
@hash[name] ? true : false
|
264
253
|
end
|
265
254
|
end
|
266
255
|
|
267
256
|
name
|
268
257
|
end
|
269
258
|
end
|
270
|
-
end
|
259
|
+
end
|