repository-support 0.1.1 → 0.1.3

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.
@@ -0,0 +1,323 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; Documentation by YARD 0.9.12
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ pathId = "README";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="file_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: README</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'><h1>Repository::Support</h1>
61
+
62
+ <p><a href="http://badge.fury.io/rb/repository-support"><img src="https://badge.fury.io/rb/repository-support.svg" alt="Gem Version" /></a>
63
+ <a href="https://codeclimate.com/github/jdickey/repository-support"><img src="https://codeclimate.com/github/jdickey/repository-support/badges/gpa.svg" alt="Code Climate" /></a>
64
+ <a href="https://codeship.com/projects/63652"> <img src="https://codeship.com/projects/224d6180-997e-0132-c9c3-165733f17d49/status?branch=master" alt="Codeship Status for jdickey/repository-support" /></a>
65
+ <a href="https://hakiri.io/github/jdickey/repository-support/master"><img src="https://hakiri.io/github/jdickey/repository-support/master.svg" alt="security" /></a>
66
+ <a href="https://gemnasium.com/jdickey/repository-support"><img src="https://gemnasium.com/jdickey/repository-support.svg" alt="Dependency Status" /></a></p>
67
+
68
+ <h2>Contents</h2>
69
+
70
+ <ul>
71
+ <li><a href="#overview">Overview</a></li>
72
+ <li><a href="#important-legacy-notice">IMPORTANT LEGACY NOTICE</a></li>
73
+ <li><a href="#installation">Installation</a></li>
74
+ <li><a href="#usage">Usage</a>
75
+ <ul>
76
+ <li><a href="#storeresult"><code>StoreResult</code></a>
77
+ <ul>
78
+ <li><a href="#storeresultsuccess"><code>StoreResult::Success</code></a></li>
79
+ <li><a href="#storeresultfailure"><code>StoreResult::Failure</code></a></li>
80
+ </ul>
81
+ </li>
82
+ <li><a href="#errorfactory"><code>ErrorFactory</code></a></li>
83
+ <li><a href="#testattributecontainer"><code>TestAttributeContainer</code></a></li>
84
+ <li><a href="#a-note-on-parameters">A Note on Parameters</a></li>
85
+ </ul>
86
+ </li>
87
+ <li><a href="#contributing">Contributing</a></li>
88
+ <li><a href="#version-history">Version History</a></li>
89
+ <li><a href="#legal">Legal</a></li>
90
+ </ul>
91
+
92
+ <h2 id="overview">Overview</h2>
93
+
94
+ <p>This Gem provides several support classes and modules for
95
+ <a href="https://github.com/jdickey/repository-base"><code>Repository::Base</code></a> and its
96
+ user-created subclasses, which implement the Repository layer of a typical Data
97
+ Mapper pattern architecture.</p>
98
+
99
+ <p>These classes and modules are:</p>
100
+
101
+ <ul>
102
+ <li><code>ErrorFactory</code> provides a single class method, <code>.create</code> which, when supplied with an <code>ActiveModel::Errors</code>-quacking object as a parameter, produces an Array of Hashes containing JSON-compatible error information;</li>
103
+ <li><code>ResultBuilder</code> is a Command-pattern class whose <code>#initialize</code> method takes one parameter and whose <code>#build</code> method evaluates that value. If it is truthy, then <code>#build</code> returns a <code>StoreResult::Success</code> (see below) with that value as its “paylaaod”. If the value is falsy, then <code>#build</code> returns a <code>StoreResult#Failure</code>, yielding the value to a block that returns the payload for the <code>StoreResult</code>.</li>
104
+ <li><code>StoreResult</code> is a simple value object with three accessors for values passed in to the <code>#initialize</code> method: namely <code>#entity</code> (some value object); <code>#success</code> (a Boolean, aliased as <code>#success?</code>); and <code>#errors</code> an Array of error records as created by <code>ErrorFactory.create</code>. It has two subclasses: <code>StoreResult::Success</code> fills in a <code>StoreResult</code> using its single parameter (the entity) and defaults for the other fields; and <code>StoreResult::Failure</code>, which does likewise initialised with an array of error hashes.</li>
105
+ <li><code>TestAttributeContainer</code> is a module that, when used to extend a class, adds an <code>attributes</code> Hash property (reader and writer) to the extending class. While <code>attributes</code> is initially empty, it may be added to either by defining a single key, or by mass-assigning a Hash to <code>attributes</code>. Once an individual “attribute” is defined for a class instance, it can be read from or written to using a direct method on that instance. See the discussion in “Usage” below for more details.</li>
106
+ </ul>
107
+
108
+ <h2 id="important-legacy-notice">IMPORTANT LEGACY NOTICE</h2>
109
+
110
+ <p><strong><em>NOTICE!</em></strong> This Gem was created to support a solo, ad-hoc, early learning experience in what is now known as Clean Architecture. It was part of our first attempt to build an alternative to the ActiveRecord/ActiveModel scheme native to Ruby on Rails.</p>
111
+
112
+ <p>As such, it has been superseded and far outshone by other, team efforts, notably <a href="http://rom-rb.org/">ROM</a> as used with <a href="http://hanamirb.org/">Hanami</a> and <a href="http://trailblazer.to/">Trailblazer</a>. You are <em>strongly advised</em> to examine these and other tools rather than to use this for <em>any</em> new development. The Gem is being republished as an 0.1.0 release purely for internal archaeologigical purposes.</p>
113
+
114
+ <h2 id="installation">Installation</h2>
115
+
116
+ <p>Add this line to your application’s Gemfile:</p>
117
+
118
+ <p><code>ruby
119
+ gem 'repository-support'
120
+ </code></p>
121
+
122
+ <p>And then execute:</p>
123
+
124
+ <pre class="code ruby"><code class="ruby">$ bundle
125
+ </code></pre>
126
+
127
+ <p>Or install it yourself as:</p>
128
+
129
+ <pre class="code ruby"><code class="ruby">$ gem install repository-support
130
+ </code></pre>
131
+
132
+ <h2 id="usage">Usage</h2>
133
+
134
+ <h3 id="storeresult"><code>StoreResult</code></h3>
135
+
136
+ <p><code>StoreReult</code> is used as the return value from all <code>Repository::Base</code> instance
137
+ methods (actions) <em>except</em> <code>#all</code>.</p>
138
+
139
+ <p>If the action implemented by the method was successful, it returns a
140
+ <code>StoreResult</code> where</p>
141
+
142
+ <ul>
143
+ <li>the <code>entity</code> attribute is an entity matching the state of the record persisted or accessed by the action;</li>
144
+ <li>the <code>success</code> attribute (or <code>#success?</code> method) is <code>true</code>; and</li>
145
+ <li>the <code>errors</code> attribute is an empty Array.</li>
146
+ </ul>
147
+
148
+ <p>If the action was unsuccessful, the repository method returns a <code>StoreResult</code>
149
+ where</p>
150
+
151
+ <ul>
152
+ <li>the <code>entity</code> attribute is <code>nil</code>;</li>
153
+ <li>the <code>success</code> attribute (or <code>#success?</code> method) is <code>false</code>; and</li>
154
+ <li>the <code>errors</code> attribute contains one error Hash for each error preventing the action from succeeding.</li>
155
+ </ul>
156
+
157
+ <h4 id="storeresultsuccess"><code>StoreResult::Success</code></h4>
158
+
159
+ <p>This subclass of <code>StoreResult</code> is a convenience for initialising a successful
160
+ <code>StoreResult</code>. Its <code>#initialize</code> method takes a single parameter, the entity to
161
+ be used in the result, with the other fields set as described above for a
162
+ successful result.</p>
163
+
164
+ <h4 id="storeresultfailure"><code>StoreResult::Failure</code></h4>
165
+
166
+ <p>This subclass of <code>StoreResult</code> is a convenience for initialising an unsuccessful
167
+ <code>StoreResult</code>. Its <code>#initialize</code> method takes a single parameter, the Array of
168
+ error hashes to be used in the result, with the other fields set as described
169
+ above for an unsuccessful result.</p>
170
+
171
+ <h3 id="errorfactory"><code>ErrorFactory</code></h3>
172
+
173
+ <p>This class has a single class method, <code>.create</code>. Given a parameter value that
174
+ quacks as an<a href="http://api.rubyonrails.org/classes/ActiveModel/Errors.html"><code>ActiveModel::Errors</code></a>
175
+ instance, it returns an Array where each item is a Hash derived from each error
176
+ reported by the parameter object, or an empty Array if there are no errors. Each
177
+ Hash in the Array has two fields:</p>
178
+
179
+ <ol>
180
+ <li><code>field</code>, which contains the attribute passed to <a href="http://api.rubyonrails.org/classes/ActiveModel/Errors.html#method-i-add"><code>ActiveModel::Errors#add</code></a> <em>as a string</em>; and</li>
181
+ <li><code>message</code>, which contains the message as passed into the same <code>#add</code> call.</li>
182
+ </ol>
183
+
184
+ <p>So, given an <code>ActiveModel::Errors</code> object that resulted from the following code:</p>
185
+
186
+ <p><code>ruby
187
+ errors = ActiveModel::Errors.new self
188
+ # ...
189
+ errors.add :frobulator, 'does not frob'
190
+ errors.add :frobulator, `is busted'
191
+ errors.add :foo, 'is :foo'
192
+ # ...
193
+ error_data = ErrorFactory.create errors
194
+ @logger.log error_data
195
+ </code></p>
196
+
197
+ <p>the value of <code>error_data</code> written to the log would be (formatted for clarity)</p>
198
+
199
+ <p><code>
200
+ [
201
+ {field: 'frobulator', message: 'does not frob'},
202
+ {field: 'frobulator', message: 'is busted'},
203
+ {field: 'foo', 'is :foo'}
204
+ ]
205
+ </code></p>
206
+
207
+ <p>Note that no guarantees are made for ordering, just as seems to be the case for
208
+ <code>ActiveModel::Errors</code>.</p>
209
+
210
+ <h3 id="testattributecontainer"><code>TestAttributeContainer</code></h3>
211
+
212
+ <p>This module implements support for attributes in a way that can be thought of as “halfway between a <a href="http://ruby-doc.org//core-2.1.5/Struct.html"><code>Struct</code></a> and an <a href="http://ruby-doc.org/stdlib-2.1.5/libdoc/ostruct/rdoc/OpenStruct.html"><code>OpenStruct</code></a> or <a href="https://github.com/tomchapin/fancy-open-struct/"><code>FancyOpenStruct</code></a>.”</p>
213
+
214
+ <p>By extending a class with the module and invoking the <code>init_empty_attribute_container</code> class method within that class, a Hash is added as the <code>attributes</code> attribute of each instance of that class. It can be assigned to directly; once having done so, individual “attributes” may be accessed <em>or modified</em> through a method call using the name of the attribute.</p>
215
+
216
+ <p>For example:</p>
217
+
218
+ <p>```ruby
219
+ class Foo
220
+ extend Repository::Support::TestAttributeContainer</p>
221
+
222
+ <p>init_empty_attribute_container
223
+ end</p>
224
+
225
+ <h1 id="interactively">interactively</h1>
226
+ <p>foo = Foo.new
227
+ # =&gt; #<Foo:0x007fd2b4b9da28>
228
+ foo.attributes
229
+ # =&gt; {}
230
+ foo.attributes = { foo: true, bar: 42 }
231
+ # =&gt; :bar=&gt;42
232
+ foo.foo
233
+ # =&gt; true
234
+ foo.foo = :whatever_you_want
235
+ # =&gt; :whatever_you_want
236
+ foo.attributes
237
+ # =&gt; :bar=&gt;42
238
+ foo.quux
239
+ # =&gt; NoMethodError: undefined method `quux' # ...
240
+ foo.attributes[:quux] = 'hello'
241
+ # =&gt; "hello"
242
+ foo.quux
243
+ # =&gt; "hello"
244
+ ```</Foo:0x007fd2b4b9da28></p>
245
+
246
+ <p>To create a new attribute after the container has been set up, assign to a new key in the <code>attributes</code> property Hash. As demonstrated above, the “attribute” can then be accessed or modified by using its name as a reader or writer method name. Without explicitly assigning to <code>attributes</code>, however, undefined methods raise errors as usual.</p>
247
+
248
+ <h3 id="a-note-on-parameters">A Note on Parameters</h3>
249
+
250
+ <p>All <em>public</em> methods having multiple arguments (including <code>#initialize</code>) in each
251
+ of the classes defined above use the keyword-argument specification introduced
252
+ in Ruby 2.0. By removing order dependency of arguments, inadvertent-reordering
253
+ errors are no longer a
254
+ <a href="http://en.wikipedia.org/wiki/Hunt_the_Wumpus">hunt-the-typo</a>
255
+ exercise. This rule <em>does not</em> apply to single-parameter methods, nor to
256
+ <code>private</code> methods.</p>
257
+
258
+ <h2 id="contributing">Contributing</h2>
259
+
260
+ <ol>
261
+ <li>Fork it ( https://github.com/jdickey/repository-support/fork )</li>
262
+ <li>Create your feature branch (<code>git checkout -b my-new-feature</code>)</li>
263
+ <li>Ensure that your changes are completely covered by <em>passing</em> specs, and comply with the <a href="https://github.com/bbatsov/ruby-style-guide">Ruby Style Guide</a> as enforced by <a href="https://github.com/bbatsov/rubocop">RuboCop</a>. To verify this, run <code>bundle exec rake</code>, noting and repairing any lapses in coverage or style violations;</li>
264
+ <li>Commit your changes (<code>git commit -a</code>). Please <em>do not</em> use a single-line commit message (<code>git commit -am "some message"</code>). A good commit message notes what was changed and why in sufficient detail that a relative newcomer to the code can understand your reasoning and your code;</li>
265
+ <li>Push to the branch (<code>git push origin my-new-feature</code>)</li>
266
+ <li>Create a new Pull Request. Describe at some length the rationale for your new feature; your implementation strategy at a higher level than each individual commit message; anything future maintainers should be aware of; and so on. <em>If this is a modification to existing code, reference the open issue being addressed</em>.</li>
267
+ <li>Don’t be discouraged if the PR generates a discussion that leads to further refinement of your PR through additional commits. These should <em>generally</em> be discussed in comments on the PR itself; discussion in the Gitter room (see below) may also be useful;</li>
268
+ <li>If you’ve comments, questions, or just want to talk through your ideas, don’t hesitate to hang out in the <code>Repository::Base</code> <a href="https://gitter.im/jdickey/repository-base">room on Gitter</a>. Ask away!</li>
269
+ </ol>
270
+
271
+ <h2 id="version-history">Version History</h2>
272
+
273
+ <table>
274
+ <thead>
275
+ <tr>
276
+ <th>Version</th>
277
+ <th>Date</th>
278
+ <th>Notes</th>
279
+ </tr>
280
+ </thead>
281
+ <tbody>
282
+ <tr>
283
+ <td>v0.1.0</td>
284
+ <td>2 February 2018</td>
285
+ <td>Changed MRI supported version from 2.2.2 to 2.5.0; <strong>published legacy notice</strong></td>
286
+ </tr>
287
+ <tr>
288
+ <td>v0.0.4</td>
289
+ <td>9 March 2015</td>
290
+ <td>Added experimental, one-off JRuby 9000 support</td>
291
+ </tr>
292
+ <tr>
293
+ <td>v0.0.3</td>
294
+ <td>21 February 2015</td>
295
+ <td>Completed initial feature development</td>
296
+ </tr>
297
+ <tr>
298
+ <td>v0.0.2</td>
299
+ <td>18 February 2015</td>
300
+ <td>Internal; incremental feature development</td>
301
+ </tr>
302
+ <tr>
303
+ <td>v0.0.1</td>
304
+ <td>18 February 2015</td>
305
+ <td>Internal; incremental feature development</td>
306
+ </tr>
307
+ </tbody>
308
+ </table>
309
+
310
+ <h2 id="legal">Legal</h2>
311
+
312
+ <p>This document and the accompanying code are Copyright © 2015-2018 by Jeff Dickey/Seven Sigma Agility, and are released under the terms of the <a href="https://opensource.org/licenses/MIT">MIT License</a>.</p>
313
+ </div></div>
314
+
315
+ <div id="footer">
316
+ Generated on Sun Feb 4 17:26:37 2018 by
317
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
318
+ 0.9.12 (ruby-2.5.0).
319
+ </div>
320
+
321
+ </div>
322
+ </body>
323
+ </html>
@@ -0,0 +1,56 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+ <meta charset="utf-8" />
6
+
7
+ <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
8
+
9
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
10
+
11
+
12
+
13
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
16
+
17
+
18
+ <title>File List</title>
19
+ <base id="base_target" target="_parent" />
20
+ </head>
21
+ <body>
22
+ <div id="content">
23
+ <div class="fixed_header">
24
+ <h1 id="full_list_header">File List</h1>
25
+ <div id="full_list_nav">
26
+
27
+ <span><a target="_self" href="class_list.html">
28
+ Classes
29
+ </a></span>
30
+
31
+ <span><a target="_self" href="method_list.html">
32
+ Methods
33
+ </a></span>
34
+
35
+ <span><a target="_self" href="file_list.html">
36
+ Files
37
+ </a></span>
38
+
39
+ </div>
40
+
41
+ <div id="search">Search: <input type="text" /></div>
42
+ </div>
43
+
44
+ <ul id="full_list" class="file">
45
+
46
+
47
+ <li id="object_README" class="odd">
48
+ <div class="item"><span class="object_link"><a href="index.html" title="README">README</a></span></div>
49
+ </li>
50
+
51
+
52
+
53
+ </ul>
54
+ </div>
55
+ </body>
56
+ </html>
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Documentation by YARD 0.9.12</title>
6
+ </head>
7
+ <script type="text/javascript" charset="utf-8">
8
+ var match = unescape(window.location.hash).match(/^#!(.+)/);
9
+ var name = match ? match[1] : 'index.html';
10
+ name = name.replace(/^(\w+):\/\//, '').replace(/^\/\//, '');
11
+ window.top.location = name;
12
+ </script>
13
+ <noscript>
14
+ <h1>Oops!</h1>
15
+ <h2>YARD requires JavaScript!</h2>
16
+ </noscript>
17
+ </html>
@@ -0,0 +1,323 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; Documentation by YARD 0.9.12
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ pathId = "README";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="class_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: README</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'><h1>Repository::Support</h1>
61
+
62
+ <p><a href="http://badge.fury.io/rb/repository-support"><img src="https://badge.fury.io/rb/repository-support.svg" alt="Gem Version" /></a>
63
+ <a href="https://codeclimate.com/github/jdickey/repository-support"><img src="https://codeclimate.com/github/jdickey/repository-support/badges/gpa.svg" alt="Code Climate" /></a>
64
+ <a href="https://codeship.com/projects/63652"> <img src="https://codeship.com/projects/224d6180-997e-0132-c9c3-165733f17d49/status?branch=master" alt="Codeship Status for jdickey/repository-support" /></a>
65
+ <a href="https://hakiri.io/github/jdickey/repository-support/master"><img src="https://hakiri.io/github/jdickey/repository-support/master.svg" alt="security" /></a>
66
+ <a href="https://gemnasium.com/jdickey/repository-support"><img src="https://gemnasium.com/jdickey/repository-support.svg" alt="Dependency Status" /></a></p>
67
+
68
+ <h2>Contents</h2>
69
+
70
+ <ul>
71
+ <li><a href="#overview">Overview</a></li>
72
+ <li><a href="#important-legacy-notice">IMPORTANT LEGACY NOTICE</a></li>
73
+ <li><a href="#installation">Installation</a></li>
74
+ <li><a href="#usage">Usage</a>
75
+ <ul>
76
+ <li><a href="#storeresult"><code>StoreResult</code></a>
77
+ <ul>
78
+ <li><a href="#storeresultsuccess"><code>StoreResult::Success</code></a></li>
79
+ <li><a href="#storeresultfailure"><code>StoreResult::Failure</code></a></li>
80
+ </ul>
81
+ </li>
82
+ <li><a href="#errorfactory"><code>ErrorFactory</code></a></li>
83
+ <li><a href="#testattributecontainer"><code>TestAttributeContainer</code></a></li>
84
+ <li><a href="#a-note-on-parameters">A Note on Parameters</a></li>
85
+ </ul>
86
+ </li>
87
+ <li><a href="#contributing">Contributing</a></li>
88
+ <li><a href="#version-history">Version History</a></li>
89
+ <li><a href="#legal">Legal</a></li>
90
+ </ul>
91
+
92
+ <h2 id="overview">Overview</h2>
93
+
94
+ <p>This Gem provides several support classes and modules for
95
+ <a href="https://github.com/jdickey/repository-base"><code>Repository::Base</code></a> and its
96
+ user-created subclasses, which implement the Repository layer of a typical Data
97
+ Mapper pattern architecture.</p>
98
+
99
+ <p>These classes and modules are:</p>
100
+
101
+ <ul>
102
+ <li><code>ErrorFactory</code> provides a single class method, <code>.create</code> which, when supplied with an <code>ActiveModel::Errors</code>-quacking object as a parameter, produces an Array of Hashes containing JSON-compatible error information;</li>
103
+ <li><code>ResultBuilder</code> is a Command-pattern class whose <code>#initialize</code> method takes one parameter and whose <code>#build</code> method evaluates that value. If it is truthy, then <code>#build</code> returns a <code>StoreResult::Success</code> (see below) with that value as its “paylaaod”. If the value is falsy, then <code>#build</code> returns a <code>StoreResult#Failure</code>, yielding the value to a block that returns the payload for the <code>StoreResult</code>.</li>
104
+ <li><code>StoreResult</code> is a simple value object with three accessors for values passed in to the <code>#initialize</code> method: namely <code>#entity</code> (some value object); <code>#success</code> (a Boolean, aliased as <code>#success?</code>); and <code>#errors</code> an Array of error records as created by <code>ErrorFactory.create</code>. It has two subclasses: <code>StoreResult::Success</code> fills in a <code>StoreResult</code> using its single parameter (the entity) and defaults for the other fields; and <code>StoreResult::Failure</code>, which does likewise initialised with an array of error hashes.</li>
105
+ <li><code>TestAttributeContainer</code> is a module that, when used to extend a class, adds an <code>attributes</code> Hash property (reader and writer) to the extending class. While <code>attributes</code> is initially empty, it may be added to either by defining a single key, or by mass-assigning a Hash to <code>attributes</code>. Once an individual “attribute” is defined for a class instance, it can be read from or written to using a direct method on that instance. See the discussion in “Usage” below for more details.</li>
106
+ </ul>
107
+
108
+ <h2 id="important-legacy-notice">IMPORTANT LEGACY NOTICE</h2>
109
+
110
+ <p><strong><em>NOTICE!</em></strong> This Gem was created to support a solo, ad-hoc, early learning experience in what is now known as Clean Architecture. It was part of our first attempt to build an alternative to the ActiveRecord/ActiveModel scheme native to Ruby on Rails.</p>
111
+
112
+ <p>As such, it has been superseded and far outshone by other, team efforts, notably <a href="http://rom-rb.org/">ROM</a> as used with <a href="http://hanamirb.org/">Hanami</a> and <a href="http://trailblazer.to/">Trailblazer</a>. You are <em>strongly advised</em> to examine these and other tools rather than to use this for <em>any</em> new development. The Gem is being republished as an 0.1.0 release purely for internal archaeologigical purposes.</p>
113
+
114
+ <h2 id="installation">Installation</h2>
115
+
116
+ <p>Add this line to your application’s Gemfile:</p>
117
+
118
+ <p><code>ruby
119
+ gem 'repository-support'
120
+ </code></p>
121
+
122
+ <p>And then execute:</p>
123
+
124
+ <pre class="code ruby"><code class="ruby">$ bundle
125
+ </code></pre>
126
+
127
+ <p>Or install it yourself as:</p>
128
+
129
+ <pre class="code ruby"><code class="ruby">$ gem install repository-support
130
+ </code></pre>
131
+
132
+ <h2 id="usage">Usage</h2>
133
+
134
+ <h3 id="storeresult"><code>StoreResult</code></h3>
135
+
136
+ <p><code>StoreReult</code> is used as the return value from all <code>Repository::Base</code> instance
137
+ methods (actions) <em>except</em> <code>#all</code>.</p>
138
+
139
+ <p>If the action implemented by the method was successful, it returns a
140
+ <code>StoreResult</code> where</p>
141
+
142
+ <ul>
143
+ <li>the <code>entity</code> attribute is an entity matching the state of the record persisted or accessed by the action;</li>
144
+ <li>the <code>success</code> attribute (or <code>#success?</code> method) is <code>true</code>; and</li>
145
+ <li>the <code>errors</code> attribute is an empty Array.</li>
146
+ </ul>
147
+
148
+ <p>If the action was unsuccessful, the repository method returns a <code>StoreResult</code>
149
+ where</p>
150
+
151
+ <ul>
152
+ <li>the <code>entity</code> attribute is <code>nil</code>;</li>
153
+ <li>the <code>success</code> attribute (or <code>#success?</code> method) is <code>false</code>; and</li>
154
+ <li>the <code>errors</code> attribute contains one error Hash for each error preventing the action from succeeding.</li>
155
+ </ul>
156
+
157
+ <h4 id="storeresultsuccess"><code>StoreResult::Success</code></h4>
158
+
159
+ <p>This subclass of <code>StoreResult</code> is a convenience for initialising a successful
160
+ <code>StoreResult</code>. Its <code>#initialize</code> method takes a single parameter, the entity to
161
+ be used in the result, with the other fields set as described above for a
162
+ successful result.</p>
163
+
164
+ <h4 id="storeresultfailure"><code>StoreResult::Failure</code></h4>
165
+
166
+ <p>This subclass of <code>StoreResult</code> is a convenience for initialising an unsuccessful
167
+ <code>StoreResult</code>. Its <code>#initialize</code> method takes a single parameter, the Array of
168
+ error hashes to be used in the result, with the other fields set as described
169
+ above for an unsuccessful result.</p>
170
+
171
+ <h3 id="errorfactory"><code>ErrorFactory</code></h3>
172
+
173
+ <p>This class has a single class method, <code>.create</code>. Given a parameter value that
174
+ quacks as an<a href="http://api.rubyonrails.org/classes/ActiveModel/Errors.html"><code>ActiveModel::Errors</code></a>
175
+ instance, it returns an Array where each item is a Hash derived from each error
176
+ reported by the parameter object, or an empty Array if there are no errors. Each
177
+ Hash in the Array has two fields:</p>
178
+
179
+ <ol>
180
+ <li><code>field</code>, which contains the attribute passed to <a href="http://api.rubyonrails.org/classes/ActiveModel/Errors.html#method-i-add"><code>ActiveModel::Errors#add</code></a> <em>as a string</em>; and</li>
181
+ <li><code>message</code>, which contains the message as passed into the same <code>#add</code> call.</li>
182
+ </ol>
183
+
184
+ <p>So, given an <code>ActiveModel::Errors</code> object that resulted from the following code:</p>
185
+
186
+ <p><code>ruby
187
+ errors = ActiveModel::Errors.new self
188
+ # ...
189
+ errors.add :frobulator, 'does not frob'
190
+ errors.add :frobulator, `is busted'
191
+ errors.add :foo, 'is :foo'
192
+ # ...
193
+ error_data = ErrorFactory.create errors
194
+ @logger.log error_data
195
+ </code></p>
196
+
197
+ <p>the value of <code>error_data</code> written to the log would be (formatted for clarity)</p>
198
+
199
+ <p><code>
200
+ [
201
+ {field: 'frobulator', message: 'does not frob'},
202
+ {field: 'frobulator', message: 'is busted'},
203
+ {field: 'foo', 'is :foo'}
204
+ ]
205
+ </code></p>
206
+
207
+ <p>Note that no guarantees are made for ordering, just as seems to be the case for
208
+ <code>ActiveModel::Errors</code>.</p>
209
+
210
+ <h3 id="testattributecontainer"><code>TestAttributeContainer</code></h3>
211
+
212
+ <p>This module implements support for attributes in a way that can be thought of as “halfway between a <a href="http://ruby-doc.org//core-2.1.5/Struct.html"><code>Struct</code></a> and an <a href="http://ruby-doc.org/stdlib-2.1.5/libdoc/ostruct/rdoc/OpenStruct.html"><code>OpenStruct</code></a> or <a href="https://github.com/tomchapin/fancy-open-struct/"><code>FancyOpenStruct</code></a>.”</p>
213
+
214
+ <p>By extending a class with the module and invoking the <code>init_empty_attribute_container</code> class method within that class, a Hash is added as the <code>attributes</code> attribute of each instance of that class. It can be assigned to directly; once having done so, individual “attributes” may be accessed <em>or modified</em> through a method call using the name of the attribute.</p>
215
+
216
+ <p>For example:</p>
217
+
218
+ <p>```ruby
219
+ class Foo
220
+ extend Repository::Support::TestAttributeContainer</p>
221
+
222
+ <p>init_empty_attribute_container
223
+ end</p>
224
+
225
+ <h1 id="interactively">interactively</h1>
226
+ <p>foo = Foo.new
227
+ # =&gt; #<Foo:0x007fd2b4b9da28>
228
+ foo.attributes
229
+ # =&gt; {}
230
+ foo.attributes = { foo: true, bar: 42 }
231
+ # =&gt; :bar=&gt;42
232
+ foo.foo
233
+ # =&gt; true
234
+ foo.foo = :whatever_you_want
235
+ # =&gt; :whatever_you_want
236
+ foo.attributes
237
+ # =&gt; :bar=&gt;42
238
+ foo.quux
239
+ # =&gt; NoMethodError: undefined method `quux' # ...
240
+ foo.attributes[:quux] = 'hello'
241
+ # =&gt; "hello"
242
+ foo.quux
243
+ # =&gt; "hello"
244
+ ```</Foo:0x007fd2b4b9da28></p>
245
+
246
+ <p>To create a new attribute after the container has been set up, assign to a new key in the <code>attributes</code> property Hash. As demonstrated above, the “attribute” can then be accessed or modified by using its name as a reader or writer method name. Without explicitly assigning to <code>attributes</code>, however, undefined methods raise errors as usual.</p>
247
+
248
+ <h3 id="a-note-on-parameters">A Note on Parameters</h3>
249
+
250
+ <p>All <em>public</em> methods having multiple arguments (including <code>#initialize</code>) in each
251
+ of the classes defined above use the keyword-argument specification introduced
252
+ in Ruby 2.0. By removing order dependency of arguments, inadvertent-reordering
253
+ errors are no longer a
254
+ <a href="http://en.wikipedia.org/wiki/Hunt_the_Wumpus">hunt-the-typo</a>
255
+ exercise. This rule <em>does not</em> apply to single-parameter methods, nor to
256
+ <code>private</code> methods.</p>
257
+
258
+ <h2 id="contributing">Contributing</h2>
259
+
260
+ <ol>
261
+ <li>Fork it ( https://github.com/jdickey/repository-support/fork )</li>
262
+ <li>Create your feature branch (<code>git checkout -b my-new-feature</code>)</li>
263
+ <li>Ensure that your changes are completely covered by <em>passing</em> specs, and comply with the <a href="https://github.com/bbatsov/ruby-style-guide">Ruby Style Guide</a> as enforced by <a href="https://github.com/bbatsov/rubocop">RuboCop</a>. To verify this, run <code>bundle exec rake</code>, noting and repairing any lapses in coverage or style violations;</li>
264
+ <li>Commit your changes (<code>git commit -a</code>). Please <em>do not</em> use a single-line commit message (<code>git commit -am "some message"</code>). A good commit message notes what was changed and why in sufficient detail that a relative newcomer to the code can understand your reasoning and your code;</li>
265
+ <li>Push to the branch (<code>git push origin my-new-feature</code>)</li>
266
+ <li>Create a new Pull Request. Describe at some length the rationale for your new feature; your implementation strategy at a higher level than each individual commit message; anything future maintainers should be aware of; and so on. <em>If this is a modification to existing code, reference the open issue being addressed</em>.</li>
267
+ <li>Don’t be discouraged if the PR generates a discussion that leads to further refinement of your PR through additional commits. These should <em>generally</em> be discussed in comments on the PR itself; discussion in the Gitter room (see below) may also be useful;</li>
268
+ <li>If you’ve comments, questions, or just want to talk through your ideas, don’t hesitate to hang out in the <code>Repository::Base</code> <a href="https://gitter.im/jdickey/repository-base">room on Gitter</a>. Ask away!</li>
269
+ </ol>
270
+
271
+ <h2 id="version-history">Version History</h2>
272
+
273
+ <table>
274
+ <thead>
275
+ <tr>
276
+ <th>Version</th>
277
+ <th>Date</th>
278
+ <th>Notes</th>
279
+ </tr>
280
+ </thead>
281
+ <tbody>
282
+ <tr>
283
+ <td>v0.1.0</td>
284
+ <td>2 February 2018</td>
285
+ <td>Changed MRI supported version from 2.2.2 to 2.5.0; <strong>published legacy notice</strong></td>
286
+ </tr>
287
+ <tr>
288
+ <td>v0.0.4</td>
289
+ <td>9 March 2015</td>
290
+ <td>Added experimental, one-off JRuby 9000 support</td>
291
+ </tr>
292
+ <tr>
293
+ <td>v0.0.3</td>
294
+ <td>21 February 2015</td>
295
+ <td>Completed initial feature development</td>
296
+ </tr>
297
+ <tr>
298
+ <td>v0.0.2</td>
299
+ <td>18 February 2015</td>
300
+ <td>Internal; incremental feature development</td>
301
+ </tr>
302
+ <tr>
303
+ <td>v0.0.1</td>
304
+ <td>18 February 2015</td>
305
+ <td>Internal; incremental feature development</td>
306
+ </tr>
307
+ </tbody>
308
+ </table>
309
+
310
+ <h2 id="legal">Legal</h2>
311
+
312
+ <p>This document and the accompanying code are Copyright © 2015-2018 by Jeff Dickey/Seven Sigma Agility, and are released under the terms of the <a href="https://opensource.org/licenses/MIT">MIT License</a>.</p>
313
+ </div></div>
314
+
315
+ <div id="footer">
316
+ Generated on Sun Feb 4 17:26:37 2018 by
317
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
318
+ 0.9.12 (ruby-2.5.0).
319
+ </div>
320
+
321
+ </div>
322
+ </body>
323
+ </html>