rep 0.1.1 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +0 -12
- data/Rakefile +6 -8
- data/docs/docco.css +500 -0
- data/docs/index.html +408 -393
- data/docs/public/fonts/aller-bold.eot +0 -0
- data/docs/public/fonts/aller-bold.ttf +0 -0
- data/docs/public/fonts/aller-bold.woff +0 -0
- data/docs/public/fonts/aller-light.eot +0 -0
- data/docs/public/fonts/aller-light.ttf +0 -0
- data/docs/public/fonts/aller-light.woff +0 -0
- data/docs/public/fonts/novecento-bold.eot +0 -0
- data/docs/public/fonts/novecento-bold.ttf +0 -0
- data/docs/public/fonts/novecento-bold.woff +0 -0
- data/docs/public/stylesheets/normalize.css +375 -0
- data/docs/rep.html +408 -393
- data/lib/rep.rb +8 -14
- data/lib/rep/version.rb +1 -1
- data/rep.gemspec +3 -2
- metadata +20 -26
- data/docs/lib/rep.html +0 -484
- data/docs/lib/rep/version.html +0 -44
- data/docs/rep/version.html +0 -44
data/lib/rep.rb
CHANGED
@@ -25,6 +25,7 @@ require 'forwardable'
|
|
25
25
|
# `JSON::generate` and `JSON::decode` are much safer to use than `Object#to_json`.
|
26
26
|
|
27
27
|
require 'json'
|
28
|
+
require 'mashed'
|
28
29
|
|
29
30
|
require 'rep/version'
|
30
31
|
module Rep
|
@@ -46,10 +47,6 @@ module Rep
|
|
46
47
|
alias fields json_fields
|
47
48
|
end
|
48
49
|
end
|
49
|
-
|
50
|
-
if defined?(Mashed)
|
51
|
-
include MashedSupport
|
52
|
-
end
|
53
50
|
}
|
54
51
|
end
|
55
52
|
|
@@ -75,21 +72,24 @@ module Rep
|
|
75
72
|
|
76
73
|
def to_hash(name = :default)
|
77
74
|
if fields = self.class.json_fields(name)
|
78
|
-
fields.
|
75
|
+
fields.each_with_object({}) do |field, memo|
|
79
76
|
field_name, method_name = field.is_a?(Hash) ? field.to_a.first : [field, field]
|
80
|
-
|
77
|
+
if self.respond_to?(method_name)
|
81
78
|
memo[field_name] = send(method_name)
|
82
|
-
|
79
|
+
else
|
83
80
|
message = "There is no method named '#{method_name}' for the class '#{self.class}' for the '#{name}' list of fields : #{e.message}"
|
84
81
|
raise NoMethodError.new(message, method_name, e.args)
|
85
82
|
end
|
86
|
-
memo
|
87
83
|
end
|
88
84
|
else
|
89
85
|
raise "There are no json fields under the name: #{name}"
|
90
86
|
end
|
91
87
|
end
|
92
88
|
|
89
|
+
def to_mash(name = :default)
|
90
|
+
Mashed::Mash.new(to_hash(name))
|
91
|
+
end
|
92
|
+
|
93
93
|
def to_json
|
94
94
|
JSON.generate(to_hash)
|
95
95
|
end
|
@@ -299,10 +299,4 @@ module Rep
|
|
299
299
|
}
|
300
300
|
end
|
301
301
|
end
|
302
|
-
|
303
|
-
module MashedSupport
|
304
|
-
def to_hash(name = :default)
|
305
|
-
Mashed::Mash.new(super)
|
306
|
-
end
|
307
|
-
end
|
308
302
|
end
|
data/lib/rep/version.rb
CHANGED
data/rep.gemspec
CHANGED
@@ -16,8 +16,9 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'mashed', '>= 0.9.0'
|
21
|
+
|
19
22
|
gem.add_development_dependency 'rake'
|
20
23
|
gem.add_development_dependency 'minitest'
|
21
|
-
gem.add_development_dependency 'rocco'
|
22
|
-
gem.add_development_dependency 'rdiscount'
|
23
24
|
end
|
metadata
CHANGED
@@ -1,45 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- myobie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - '>='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - '>='
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: minitest
|
14
|
+
name: mashed
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - '>='
|
32
18
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
type: :
|
19
|
+
version: 0.9.0
|
20
|
+
type: :runtime
|
35
21
|
prerelease: false
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
24
|
- - '>='
|
39
25
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
26
|
+
version: 0.9.0
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
28
|
+
name: rake
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - '>='
|
@@ -53,7 +39,7 @@ dependencies:
|
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
42
|
+
name: minitest
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
45
|
- - '>='
|
@@ -80,11 +66,19 @@ files:
|
|
80
66
|
- LICENSE.txt
|
81
67
|
- README.md
|
82
68
|
- Rakefile
|
69
|
+
- docs/docco.css
|
83
70
|
- docs/index.html
|
84
|
-
- docs/
|
85
|
-
- docs/
|
71
|
+
- docs/public/fonts/aller-bold.eot
|
72
|
+
- docs/public/fonts/aller-bold.ttf
|
73
|
+
- docs/public/fonts/aller-bold.woff
|
74
|
+
- docs/public/fonts/aller-light.eot
|
75
|
+
- docs/public/fonts/aller-light.ttf
|
76
|
+
- docs/public/fonts/aller-light.woff
|
77
|
+
- docs/public/fonts/novecento-bold.eot
|
78
|
+
- docs/public/fonts/novecento-bold.ttf
|
79
|
+
- docs/public/fonts/novecento-bold.woff
|
80
|
+
- docs/public/stylesheets/normalize.css
|
86
81
|
- docs/rep.html
|
87
|
-
- docs/rep/version.html
|
88
82
|
- lib/rep.rb
|
89
83
|
- lib/rep/version.rb
|
90
84
|
- rep.gemspec
|
@@ -109,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
103
|
version: '0'
|
110
104
|
requirements: []
|
111
105
|
rubyforge_project:
|
112
|
-
rubygems_version: 2.0.
|
106
|
+
rubygems_version: 2.0.2
|
113
107
|
signing_key:
|
114
108
|
specification_version: 4
|
115
109
|
summary: Include Rep into any object to endow it to create json (or hashes) easily.
|
data/docs/lib/rep.html
DELETED
@@ -1,484 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
5
|
-
<title>rep.rb</title>
|
6
|
-
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<div id='container'>
|
10
|
-
<div id="background"></div>
|
11
|
-
<div id="jump_to">
|
12
|
-
Jump To …
|
13
|
-
<div id="jump_wrapper">
|
14
|
-
<div id="jump_page">
|
15
|
-
<a class="source" href="rep.html">rep.rb</a>
|
16
|
-
<a class="source" href="rep/version.html">version.rb</a>
|
17
|
-
</div>
|
18
|
-
</div>
|
19
|
-
</div>
|
20
|
-
<table cellspacing=0 cellpadding=0>
|
21
|
-
<thead>
|
22
|
-
<tr>
|
23
|
-
<th class=docs><h1>rep.rb</h1></th>
|
24
|
-
<th class=code></th>
|
25
|
-
</tr>
|
26
|
-
</thead>
|
27
|
-
<tbody>
|
28
|
-
<tr id='section-1'>
|
29
|
-
<td class=docs>
|
30
|
-
<div class="pilwrap">
|
31
|
-
<a class="pilcrow" href="#section-1">¶</a>
|
32
|
-
</div>
|
33
|
-
<p><strong>Rep</strong> is a small module to endow any class to make json quickly. It solves four problems:</p>
|
34
|
-
|
35
|
-
<ol>
|
36
|
-
<li>Enumerating top level keys for a json structure</li>
|
37
|
-
<li>Providing a convention for the value of those keys</li>
|
38
|
-
<li>Defining <code>attr_accessor</code>’s that are prefilled from an options hash given to <code>#initialize</code></li>
|
39
|
-
<li>Sharing instances to help GC</li>
|
40
|
-
</ol>
|
41
|
-
|
42
|
-
|
43
|
-
<p>The code is available on <a href="http://github.com/myobie/rep">github</a>.</p>
|
44
|
-
</td>
|
45
|
-
<td class=code>
|
46
|
-
<div class='highlight'><pre></pre></div>
|
47
|
-
</td>
|
48
|
-
</tr>
|
49
|
-
<tr id='section-2'>
|
50
|
-
<td class=docs>
|
51
|
-
<div class="pilwrap">
|
52
|
-
<a class="pilcrow" href="#section-2">¶</a>
|
53
|
-
</div>
|
54
|
-
<p><code>Forwardable</code> is in the stdlib and allows ruby objects to delegate methods off to other objects. An example:</p>
|
55
|
-
|
56
|
-
<pre><code>class A
|
57
|
-
extend Forwardable
|
58
|
-
delegate [:length, :first] => :@array
|
59
|
-
def initialize(array = [])
|
60
|
-
@array = array
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
A.new([1,2,3]).length # => 3
|
65
|
-
A.new([1,2,3]).first # => 1
|
66
|
-
</code></pre>
|
67
|
-
</td>
|
68
|
-
<td class=code>
|
69
|
-
<div class='highlight'><pre><span class="nb">require</span> <span class="s1">'forwardable'</span></pre></div>
|
70
|
-
</td>
|
71
|
-
</tr>
|
72
|
-
<tr id='section-3'>
|
73
|
-
<td class=docs>
|
74
|
-
<div class="pilwrap">
|
75
|
-
<a class="pilcrow" href="#section-3">¶</a>
|
76
|
-
</div>
|
77
|
-
<p><code>JSON::generate</code> and <code>JSON::decode</code> are much safer to use than <code>Object#to_json</code>.</p>
|
78
|
-
</td>
|
79
|
-
<td class=code>
|
80
|
-
<div class='highlight'><pre><span class="nb">require</span> <span class="s1">'json'</span>
|
81
|
-
|
82
|
-
<span class="nb">require</span> <span class="s1">'rep/version'</span>
|
83
|
-
<span class="k">module</span> <span class="nn">Rep</span></pre></div>
|
84
|
-
</td>
|
85
|
-
</tr>
|
86
|
-
<tr id='section-4'>
|
87
|
-
<td class=docs>
|
88
|
-
<div class="pilwrap">
|
89
|
-
<a class="pilcrow" href="#section-4">¶</a>
|
90
|
-
</div>
|
91
|
-
<p>All classes that <code>include Rep</code> are extended with <code>Forwardable</code>,
|
92
|
-
given some aliases, endowned with <code>HashieSupport</code> if Hashie is loaded,
|
93
|
-
and given a delegate method if it doesn’t already have one.</p>
|
94
|
-
</td>
|
95
|
-
<td class=code>
|
96
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">included</span><span class="p">(</span><span class="n">klass</span><span class="p">)</span>
|
97
|
-
<span class="n">klass</span><span class="o">.</span><span class="n">extend</span> <span class="no">Forwardable</span>
|
98
|
-
<span class="n">klass</span><span class="o">.</span><span class="n">extend</span> <span class="no">ClassMethods</span>
|
99
|
-
<span class="n">klass</span><span class="o">.</span><span class="n">instance_eval</span> <span class="p">{</span>
|
100
|
-
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
|
101
|
-
<span class="k">unless</span> <span class="n">defined?</span><span class="p">(</span><span class="n">forward</span><span class="p">)</span>
|
102
|
-
<span class="k">alias</span> <span class="n">forward</span> <span class="n">delegate</span>
|
103
|
-
<span class="k">end</span>
|
104
|
-
|
105
|
-
<span class="k">unless</span> <span class="n">defined?</span><span class="p">(</span><span class="n">fields</span><span class="p">)</span>
|
106
|
-
<span class="k">alias</span> <span class="n">fields</span> <span class="n">json_fields</span>
|
107
|
-
<span class="k">end</span>
|
108
|
-
<span class="k">end</span>
|
109
|
-
|
110
|
-
<span class="k">if</span> <span class="n">defined?</span><span class="p">(</span><span class="no">Mashed</span><span class="p">)</span>
|
111
|
-
<span class="kp">include</span> <span class="no">MashedSupport</span>
|
112
|
-
<span class="k">end</span>
|
113
|
-
<span class="p">}</span>
|
114
|
-
<span class="k">end</span></pre></div>
|
115
|
-
</td>
|
116
|
-
</tr>
|
117
|
-
<tr id='section-5'>
|
118
|
-
<td class=docs>
|
119
|
-
<div class="pilwrap">
|
120
|
-
<a class="pilcrow" href="#section-5">¶</a>
|
121
|
-
</div>
|
122
|
-
<p>Since a goal is to be able to share instances, we need an easy way to reset a
|
123
|
-
shared instance back to factory defaults. If you memoize any methods that are
|
124
|
-
not declared as json fields, then overried this method and set any memoized
|
125
|
-
variables to nil, then super.</p>
|
126
|
-
</td>
|
127
|
-
<td class=code>
|
128
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">reset_for_json!</span>
|
129
|
-
<span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">all_json_methods</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">method_name</span><span class="o">|</span>
|
130
|
-
<span class="nb">instance_variable_set</span><span class="p">(</span><span class="ss">:"@</span><span class="si">#{</span><span class="n">method_name</span><span class="si">}</span><span class="ss">"</span><span class="p">,</span> <span class="kp">nil</span><span class="p">)</span>
|
131
|
-
<span class="k">end</span>
|
132
|
-
<span class="k">end</span></pre></div>
|
133
|
-
</td>
|
134
|
-
</tr>
|
135
|
-
<tr id='section-6'>
|
136
|
-
<td class=docs>
|
137
|
-
<div class="pilwrap">
|
138
|
-
<a class="pilcrow" href="#section-6">¶</a>
|
139
|
-
</div>
|
140
|
-
<p>All the work of generating a hash from an instance is packaged up in one method. Since
|
141
|
-
fields can be aliases in the format <code>{ :json_key_name => :method_name }</code>, there
|
142
|
-
is some fancy logic to determine the <code>field_name</code> and <code>method_name</code> variables.</p>
|
143
|
-
|
144
|
-
<pre><code>{ :one => :foo }.to_a # => [[:one, :foo]]
|
145
|
-
</code></pre>
|
146
|
-
|
147
|
-
<p>Right now it will raise if either a field doesn’t have a method to provide it’s value or
|
148
|
-
if there are no json fields setup for the particular set (which defaults to <code>:default</code>).</p>
|
149
|
-
</td>
|
150
|
-
<td class=code>
|
151
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">to_hash</span><span class="p">(</span><span class="nb">name</span> <span class="o">=</span> <span class="ss">:default</span><span class="p">)</span>
|
152
|
-
<span class="k">if</span> <span class="n">fields</span> <span class="o">=</span> <span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">json_fields</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
|
153
|
-
<span class="n">fields</span><span class="o">.</span><span class="n">reduce</span><span class="p">({})</span> <span class="k">do</span> <span class="o">|</span><span class="n">memo</span><span class="p">,</span> <span class="n">field</span><span class="o">|</span>
|
154
|
-
<span class="n">field_name</span><span class="p">,</span> <span class="n">method_name</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Hash</span><span class="p">)</span> <span class="p">?</span> <span class="n">field</span><span class="o">.</span><span class="n">to_a</span><span class="o">.</span><span class="n">first</span> <span class="p">:</span> <span class="o">[</span><span class="n">field</span><span class="p">,</span> <span class="n">field</span><span class="o">]</span>
|
155
|
-
<span class="k">begin</span>
|
156
|
-
<span class="n">memo</span><span class="o">[</span><span class="n">field_name</span><span class="o">]</span> <span class="o">=</span> <span class="nb">send</span><span class="p">(</span><span class="n">method_name</span><span class="p">)</span>
|
157
|
-
<span class="k">rescue</span> <span class="no">NoMethodError</span> <span class="o">=></span> <span class="n">e</span>
|
158
|
-
<span class="n">message</span> <span class="o">=</span> <span class="s2">"There is no method named '</span><span class="si">#{</span><span class="n">method_name</span><span class="si">}</span><span class="s2">' for the class '</span><span class="si">#{</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="si">}</span><span class="s2">' for the '</span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">' list of fields : </span><span class="si">#{</span><span class="n">e</span><span class="o">.</span><span class="n">message</span><span class="si">}</span><span class="s2">"</span>
|
159
|
-
<span class="k">raise</span> <span class="no">NoMethodError</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">method_name</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
|
160
|
-
<span class="k">end</span>
|
161
|
-
<span class="n">memo</span>
|
162
|
-
<span class="k">end</span>
|
163
|
-
<span class="k">else</span>
|
164
|
-
<span class="k">raise</span> <span class="s2">"There are no json fields under the name: </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
|
165
|
-
<span class="k">end</span>
|
166
|
-
<span class="k">end</span>
|
167
|
-
|
168
|
-
<span class="k">def</span> <span class="nf">to_json</span>
|
169
|
-
<span class="no">JSON</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">to_hash</span><span class="p">)</span>
|
170
|
-
<span class="k">end</span>
|
171
|
-
|
172
|
-
<span class="k">module</span> <span class="nn">ClassMethods</span></pre></div>
|
173
|
-
</td>
|
174
|
-
</tr>
|
175
|
-
<tr id='section-7'>
|
176
|
-
<td class=docs>
|
177
|
-
<div class="pilwrap">
|
178
|
-
<a class="pilcrow" href="#section-7">¶</a>
|
179
|
-
</div>
|
180
|
-
<p>Defines an attr_accessor with a default value. The default for default is nil. Example:</p>
|
181
|
-
|
182
|
-
<pre><code>class A
|
183
|
-
register_accessor :name => "No Name"
|
184
|
-
end
|
185
|
-
|
186
|
-
A.new.name # => "No Name"
|
187
|
-
</code></pre>
|
188
|
-
</td>
|
189
|
-
<td class=code>
|
190
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">register_accessor</span><span class="p">(</span><span class="n">acc</span><span class="p">)</span>
|
191
|
-
<span class="nb">name</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">acc</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Hash</span><span class="p">)</span> <span class="p">?</span> <span class="n">acc</span><span class="o">.</span><span class="n">to_a</span><span class="o">.</span><span class="n">first</span> <span class="p">:</span> <span class="o">[</span><span class="n">acc</span><span class="p">,</span> <span class="kp">nil</span><span class="o">]</span>
|
192
|
-
<span class="kp">attr_accessor</span> <span class="nb">name</span>
|
193
|
-
<span class="k">if</span> <span class="n">default</span>
|
194
|
-
<span class="n">define_method</span> <span class="nb">name</span> <span class="k">do</span>
|
195
|
-
<span class="n">var_name</span> <span class="o">=</span> <span class="ss">:"@</span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="ss">"</span>
|
196
|
-
<span class="nb">instance_variable_get</span><span class="p">(</span><span class="n">var_name</span><span class="p">)</span> <span class="o">||</span> <span class="nb">instance_variable_set</span><span class="p">(</span><span class="n">var_name</span><span class="p">,</span> <span class="n">default</span><span class="p">)</span>
|
197
|
-
<span class="k">end</span>
|
198
|
-
<span class="k">end</span>
|
199
|
-
<span class="k">end</span></pre></div>
|
200
|
-
</td>
|
201
|
-
</tr>
|
202
|
-
<tr id='section-8'>
|
203
|
-
<td class=docs>
|
204
|
-
<div class="pilwrap">
|
205
|
-
<a class="pilcrow" href="#section-8">¶</a>
|
206
|
-
</div>
|
207
|
-
<p>Defines an <code>#initialize</code> method that accepts a Hash argument and copies some keys out into <code>attr_accessors</code>.
|
208
|
-
If your class already has an <code>#iniatialize</code> method then this will overwrite it (so don’t use it). <code>#initialize_with</code>
|
209
|
-
does not have to be used to use any other parts of Rep.</p>
|
210
|
-
</td>
|
211
|
-
<td class=code>
|
212
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">initialize_with</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
|
213
|
-
<span class="vi">@initializiation_args</span> <span class="o">=</span> <span class="n">args</span></pre></div>
|
214
|
-
</td>
|
215
|
-
</tr>
|
216
|
-
<tr id='section-9'>
|
217
|
-
<td class=docs>
|
218
|
-
<div class="pilwrap">
|
219
|
-
<a class="pilcrow" href="#section-9">¶</a>
|
220
|
-
</div>
|
221
|
-
<p>Remember what args we normally initialize with so we can refer to them when building shared instances.</p>
|
222
|
-
</td>
|
223
|
-
<td class=code>
|
224
|
-
<div class='highlight'><pre> <span class="k">if</span> <span class="n">defined?</span><span class="p">(</span><span class="n">define_singleton_method</span><span class="p">)</span>
|
225
|
-
<span class="n">define_singleton_method</span> <span class="ss">:initializiation_args</span> <span class="k">do</span>
|
226
|
-
<span class="vi">@initializiation_args</span>
|
227
|
-
<span class="k">end</span>
|
228
|
-
<span class="k">else</span>
|
229
|
-
<span class="n">singleton</span> <span class="o">=</span> <span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span><span class="p">;</span> <span class="nb">self</span> <span class="k">end</span>
|
230
|
-
<span class="n">singleton</span><span class="o">.</span><span class="n">send</span> <span class="ss">:define_method</span><span class="p">,</span> <span class="ss">:initializiation_args</span><span class="p">,</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="vi">@initializiation_args</span> <span class="p">}</span>
|
231
|
-
<span class="k">end</span></pre></div>
|
232
|
-
</td>
|
233
|
-
</tr>
|
234
|
-
<tr id='section-10'>
|
235
|
-
<td class=docs>
|
236
|
-
<div class="pilwrap">
|
237
|
-
<a class="pilcrow" href="#section-10">¶</a>
|
238
|
-
</div>
|
239
|
-
<p>Create an <code>attr_accessor</code> for each one. Defaults can be provided using the Hash version { :arg => :default_value }</p>
|
240
|
-
</td>
|
241
|
-
<td class=code>
|
242
|
-
<div class='highlight'><pre> <span class="n">args</span><span class="o">.</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="o">|</span> <span class="n">register_accessor</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="p">}</span>
|
243
|
-
|
244
|
-
<span class="n">define_method</span><span class="p">(</span><span class="ss">:initialize</span><span class="p">)</span> <span class="p">{</span> <span class="o">|*</span><span class="n">args</span><span class="o">|</span>
|
245
|
-
<span class="n">opts</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">first</span> <span class="o">||</span> <span class="p">{}</span>
|
246
|
-
<span class="n">parse_opts</span><span class="p">(</span><span class="n">opts</span><span class="p">)</span>
|
247
|
-
<span class="p">}</span></pre></div>
|
248
|
-
</td>
|
249
|
-
</tr>
|
250
|
-
<tr id='section-11'>
|
251
|
-
<td class=docs>
|
252
|
-
<div class="pilwrap">
|
253
|
-
<a class="pilcrow" href="#section-11">¶</a>
|
254
|
-
</div>
|
255
|
-
<p><code>#parse_opts</code> is responsable for getting the <code>attr_accessor</code> values prefilled. Since defaults can be specified, it
|
256
|
-
must negotiate Hashes and use the first key of the hash for the <code>attr_accessor</code>’s name.</p>
|
257
|
-
</td>
|
258
|
-
<td class=code>
|
259
|
-
<div class='highlight'><pre> <span class="n">define_method</span> <span class="ss">:parse_opts</span> <span class="k">do</span> <span class="o">|</span><span class="n">opts</span><span class="o">|</span>
|
260
|
-
<span class="vi">@rep_options</span> <span class="o">=</span> <span class="n">opts</span>
|
261
|
-
<span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">initializiation_args</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">field</span><span class="o">|</span>
|
262
|
-
<span class="nb">name</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Hash</span><span class="p">)</span> <span class="p">?</span> <span class="n">field</span><span class="o">.</span><span class="n">to_a</span><span class="o">.</span><span class="n">first</span><span class="o">.</span><span class="n">first</span> <span class="p">:</span> <span class="n">field</span>
|
263
|
-
<span class="nb">instance_variable_set</span><span class="p">(</span><span class="ss">:"@</span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="ss">"</span><span class="p">,</span> <span class="n">opts</span><span class="o">[</span><span class="nb">name</span><span class="o">]</span><span class="p">)</span>
|
264
|
-
<span class="k">end</span>
|
265
|
-
<span class="k">end</span>
|
266
|
-
<span class="k">end</span></pre></div>
|
267
|
-
</td>
|
268
|
-
</tr>
|
269
|
-
<tr id='section-12'>
|
270
|
-
<td class=docs>
|
271
|
-
<div class="pilwrap">
|
272
|
-
<a class="pilcrow" href="#section-12">¶</a>
|
273
|
-
</div>
|
274
|
-
<p><code>#json_fields</code> setups up some class instance variables to remember sets of top level keys for json structures. Example:</p>
|
275
|
-
|
276
|
-
<pre><code>class A
|
277
|
-
json_fields [:one, :two, :three] => :default
|
278
|
-
end
|
279
|
-
|
280
|
-
A.json_fields(:default) # => [:one, :two, :three]
|
281
|
-
</code></pre>
|
282
|
-
|
283
|
-
<p>There is a general assumption that each top level key’s value is provided by a method of the same name on an instance
|
284
|
-
of the class. If this is not true, a Hash syntax can be used to alias to a different method name. Example:</p>
|
285
|
-
|
286
|
-
<pre><code>class A
|
287
|
-
json_fields [{ :one => :the_real_one_method }, :two, { :three => :some_other_three }] => :default
|
288
|
-
end
|
289
|
-
</code></pre>
|
290
|
-
|
291
|
-
<p>Once can also set multiple sets of fields. Example:</p>
|
292
|
-
|
293
|
-
<pre><code>class A
|
294
|
-
json_fields [:one, :two, :three] => :default
|
295
|
-
json_fields [:five, :two, :six] => :other
|
296
|
-
end
|
297
|
-
</code></pre>
|
298
|
-
|
299
|
-
<p>And all fields are returned by calling <code>#json_fields</code> with no args. Example:</p>
|
300
|
-
|
301
|
-
<pre><code>A.json_fields # => { :default => [:one, :two, :three], :other => [:five, :two, :six] }
|
302
|
-
</code></pre>
|
303
|
-
</td>
|
304
|
-
<td class=code>
|
305
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">json_fields</span><span class="p">(</span><span class="n">arg</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
|
306
|
-
<span class="k">if</span> <span class="n">arg</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Hash</span><span class="p">)</span>
|
307
|
-
<span class="n">fields</span><span class="p">,</span> <span class="nb">name</span> <span class="o">=</span> <span class="n">arg</span><span class="o">.</span><span class="n">to_a</span><span class="o">.</span><span class="n">first</span>
|
308
|
-
<span class="vi">@json_fields</span> <span class="o">||=</span> <span class="p">{}</span>
|
309
|
-
<span class="vi">@json_fields</span><span class="o">[</span><span class="nb">name</span><span class="o">]</span> <span class="o">=</span> <span class="o">[</span><span class="n">fields</span><span class="o">].</span><span class="n">flatten</span>
|
310
|
-
<span class="k">elsif</span> <span class="n">arg</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Symbol</span><span class="p">)</span>
|
311
|
-
<span class="vi">@json_fields</span> <span class="o">||=</span> <span class="p">{}</span>
|
312
|
-
<span class="vi">@json_fields</span><span class="o">[</span><span class="n">arg</span><span class="o">]</span>
|
313
|
-
<span class="k">elsif</span> <span class="n">arg</span> <span class="o">===</span> <span class="kp">nil</span>
|
314
|
-
<span class="vi">@json_fields</span> <span class="o">||</span> <span class="p">{}</span>
|
315
|
-
<span class="k">else</span></pre></div>
|
316
|
-
</td>
|
317
|
-
</tr>
|
318
|
-
<tr id='section-13'>
|
319
|
-
<td class=docs>
|
320
|
-
<div class="pilwrap">
|
321
|
-
<a class="pilcrow" href="#section-13">¶</a>
|
322
|
-
</div>
|
323
|
-
<p>TODO: make an exception class</p>
|
324
|
-
</td>
|
325
|
-
<td class=code>
|
326
|
-
<div class='highlight'><pre> <span class="k">raise</span> <span class="s2">"You can only use a Hash to set fields, a Symbol to retrieve them, or no argument to retrieve all fields for all names"</span>
|
327
|
-
<span class="k">end</span>
|
328
|
-
<span class="k">end</span></pre></div>
|
329
|
-
</td>
|
330
|
-
</tr>
|
331
|
-
<tr id='section-14'>
|
332
|
-
<td class=docs>
|
333
|
-
<div class="pilwrap">
|
334
|
-
<a class="pilcrow" href="#section-14">¶</a>
|
335
|
-
</div>
|
336
|
-
<p><code>#flat_json_fields</code> is just a utility method to DRY up the next two methods, because their code is almost exactly the same,
|
337
|
-
it is not intended for use directly and might be confusing.</p>
|
338
|
-
</td>
|
339
|
-
<td class=code>
|
340
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">flat_json_fields</span><span class="p">(</span><span class="n">side</span> <span class="o">=</span> <span class="ss">:right</span><span class="p">)</span>
|
341
|
-
<span class="n">side_number</span> <span class="o">=</span> <span class="n">side</span> <span class="o">==</span> <span class="ss">:right</span> <span class="p">?</span> <span class="mi">1</span> <span class="p">:</span> <span class="mi">0</span>
|
342
|
-
|
343
|
-
<span class="n">json_fields</span><span class="o">.</span><span class="n">reduce</span><span class="p">(</span><span class="o">[]</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">memo</span><span class="p">,</span> <span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">fields</span><span class="p">)</span><span class="o">|</span>
|
344
|
-
<span class="n">memo</span> <span class="o">+</span> <span class="n">fields</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">field</span><span class="o">|</span>
|
345
|
-
<span class="k">if</span> <span class="n">field</span><span class="o">.</span><span class="n">is_a?</span><span class="p">(</span><span class="no">Hash</span><span class="p">)</span>
|
346
|
-
<span class="n">field</span><span class="o">.</span><span class="n">to_a</span><span class="o">.</span><span class="n">first</span><span class="o">[</span><span class="n">side_number</span><span class="o">]</span> <span class="c1"># [name, method_name]</span>
|
347
|
-
<span class="k">else</span>
|
348
|
-
<span class="n">field</span>
|
349
|
-
<span class="k">end</span>
|
350
|
-
<span class="k">end</span>
|
351
|
-
<span class="k">end</span><span class="o">.</span><span class="n">uniq</span>
|
352
|
-
<span class="k">end</span></pre></div>
|
353
|
-
</td>
|
354
|
-
</tr>
|
355
|
-
<tr id='section-15'>
|
356
|
-
<td class=docs>
|
357
|
-
<div class="pilwrap">
|
358
|
-
<a class="pilcrow" href="#section-15">¶</a>
|
359
|
-
</div>
|
360
|
-
<p>We need a way to get a flat, uniq'ed list of all the fields accross all field sets. This is that.</p>
|
361
|
-
</td>
|
362
|
-
<td class=code>
|
363
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">all_json_fields</span>
|
364
|
-
<span class="n">flat_json_fields</span><span class="p">(</span><span class="ss">:left</span><span class="p">)</span>
|
365
|
-
<span class="k">end</span></pre></div>
|
366
|
-
</td>
|
367
|
-
</tr>
|
368
|
-
<tr id='section-16'>
|
369
|
-
<td class=docs>
|
370
|
-
<div class="pilwrap">
|
371
|
-
<a class="pilcrow" href="#section-16">¶</a>
|
372
|
-
</div>
|
373
|
-
<p>We need a wya to get a flat, uniq'ed list of all the method names accross all field sets. This is that.</p>
|
374
|
-
</td>
|
375
|
-
<td class=code>
|
376
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">all_json_methods</span>
|
377
|
-
<span class="n">flat_json_fields</span><span class="p">(</span><span class="ss">:right</span><span class="p">)</span>
|
378
|
-
<span class="k">end</span></pre></div>
|
379
|
-
</td>
|
380
|
-
</tr>
|
381
|
-
<tr id='section-17'>
|
382
|
-
<td class=docs>
|
383
|
-
<div class="pilwrap">
|
384
|
-
<a class="pilcrow" href="#section-17">¶</a>
|
385
|
-
</div>
|
386
|
-
<p>An easy way to save on GC is to use the same instance to turn an array of objects into hashes instead
|
387
|
-
of instantiating a new object for every object in the array. Here is an example of it’s usage:</p>
|
388
|
-
|
389
|
-
<pre><code>class BookRep
|
390
|
-
initialize_with :book_model
|
391
|
-
fields :title => :default
|
392
|
-
forward :title => :book_model
|
393
|
-
end
|
394
|
-
|
395
|
-
BookRep.shared(:book_model => Book.first).to_hash # => { :title => "Moby Dick" }
|
396
|
-
BookRep.shared(:book_model => Book.last).to_hash # => { :title => "Lost Horizon" }
|
397
|
-
</code></pre>
|
398
|
-
|
399
|
-
<p>This should terrify you. If it doesn’t, then this example will:</p>
|
400
|
-
|
401
|
-
<pre><code>book1 = BookRep.shared(:book_model => Book.first)
|
402
|
-
book2 = BookRep.shared(:book_model => Book.last)
|
403
|
-
|
404
|
-
boo1.object_id === book2.object_id # => true
|
405
|
-
</code></pre>
|
406
|
-
|
407
|
-
<p><strong>It really is a shared object.</strong></p>
|
408
|
-
|
409
|
-
<p>You really shouldn’t use this method directly for anything.</p>
|
410
|
-
</td>
|
411
|
-
<td class=code>
|
412
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">shared</span><span class="p">(</span><span class="n">opts</span> <span class="o">=</span> <span class="p">{})</span>
|
413
|
-
<span class="vi">@pointer</span> <span class="o">=</span> <span class="p">(</span><span class="no">Thread</span><span class="o">.</span><span class="n">current</span><span class="o">[</span><span class="ss">:rep_shared_instances</span><span class="o">]</span> <span class="o">||=</span> <span class="p">{})</span>
|
414
|
-
<span class="vi">@pointer</span><span class="o">[</span><span class="nb">object_id</span><span class="o">]</span> <span class="o">||=</span> <span class="kp">new</span>
|
415
|
-
<span class="vi">@pointer</span><span class="o">[</span><span class="nb">object_id</span><span class="o">].</span><span class="n">reset_for_json!</span>
|
416
|
-
<span class="vi">@pointer</span><span class="o">[</span><span class="nb">object_id</span><span class="o">].</span><span class="n">parse_opts</span><span class="p">(</span><span class="n">opts</span><span class="p">)</span>
|
417
|
-
<span class="vi">@pointer</span><span class="o">[</span><span class="nb">object_id</span><span class="o">]</span>
|
418
|
-
<span class="k">end</span></pre></div>
|
419
|
-
</td>
|
420
|
-
</tr>
|
421
|
-
<tr id='section-18'>
|
422
|
-
<td class=docs>
|
423
|
-
<div class="pilwrap">
|
424
|
-
<a class="pilcrow" href="#section-18">¶</a>
|
425
|
-
</div>
|
426
|
-
<p>The fanciest thing in this entire library is this <code>#to_proc</code> method. Here is an example of it’s usage:</p>
|
427
|
-
|
428
|
-
<pre><code>class BookRep
|
429
|
-
initialize_with :book_model
|
430
|
-
fields :title => :default
|
431
|
-
forward :title => :book_model
|
432
|
-
end
|
433
|
-
|
434
|
-
Book.all.map(&BookRep) # => [{ :title => "Moby Dick" }, { :title => "Lost Horizon " }]
|
435
|
-
</code></pre>
|
436
|
-
|
437
|
-
<p>And now I will explain how it works. Any object can have a to_proc method and when you call <code>#map</code> on an
|
438
|
-
array and hand it a proc it will in turn hand each object as an argument to that proc. What I’ve decided
|
439
|
-
to do with this object is use it the options for a shared instance to make a hash.</p>
|
440
|
-
|
441
|
-
<p>Since I know the different initialization argumants from a call to <code>initialize_with</code>, I can infer by order
|
442
|
-
which object is which option. Then I can create a Hash to give to <code>parse_opts</code> through the <code>shared</code> method.
|
443
|
-
I hope that makes sense.</p>
|
444
|
-
|
445
|
-
<p>It allows for extremely clean Rails controllers like this:</p>
|
446
|
-
|
447
|
-
<pre><code>class PhotosController < ApplicationController
|
448
|
-
respond_to :json, :html
|
449
|
-
|
450
|
-
def index
|
451
|
-
@photos = Photo.paginate(page: params[:page], per_page: 20)
|
452
|
-
respond_with @photos.map(&PhotoRep)
|
453
|
-
end
|
454
|
-
|
455
|
-
def show
|
456
|
-
@photo = Photo.find(params[:id])
|
457
|
-
respond_with PhotoRep.new(photo: @photo)
|
458
|
-
end
|
459
|
-
end
|
460
|
-
</code></pre>
|
461
|
-
|
462
|
-
</td>
|
463
|
-
<td class=code>
|
464
|
-
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">to_proc</span>
|
465
|
-
<span class="nb">proc</span> <span class="p">{</span> <span class="o">|</span><span class="n">obj</span><span class="o">|</span>
|
466
|
-
<span class="n">arr</span> <span class="o">=</span> <span class="o">[</span><span class="n">obj</span><span class="o">].</span><span class="n">flatten</span>
|
467
|
-
<span class="n">init_args</span> <span class="o">=</span> <span class="vi">@initializiation_args</span><span class="o">[</span><span class="mi">0</span><span class="o">.</span><span class="n">.</span><span class="p">(</span><span class="n">arr</span><span class="o">.</span><span class="n">length</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">]</span>
|
468
|
-
<span class="n">opts</span> <span class="o">=</span> <span class="no">Hash</span><span class="o">[</span><span class="n">init_args</span><span class="o">.</span><span class="n">zip</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span><span class="o">]</span>
|
469
|
-
<span class="n">shared</span><span class="p">(</span><span class="n">opts</span><span class="p">)</span><span class="o">.</span><span class="n">to_hash</span>
|
470
|
-
<span class="p">}</span>
|
471
|
-
<span class="k">end</span>
|
472
|
-
<span class="k">end</span>
|
473
|
-
|
474
|
-
<span class="k">module</span> <span class="nn">MashedSupport</span>
|
475
|
-
<span class="k">def</span> <span class="nf">to_hash</span><span class="p">(</span><span class="nb">name</span> <span class="o">=</span> <span class="ss">:default</span><span class="p">)</span>
|
476
|
-
<span class="no">Mashed</span><span class="o">::</span><span class="no">Mash</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="k">super</span><span class="p">)</span>
|
477
|
-
<span class="k">end</span>
|
478
|
-
<span class="k">end</span>
|
479
|
-
<span class="k">end</span></pre></div>
|
480
|
-
</td>
|
481
|
-
</tr>
|
482
|
-
</table>
|
483
|
-
</div>
|
484
|
-
</body>
|