repository-support 0.1.1

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,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d697e19788520158f868c0deeaadb25da7d12ea3001cca38f3efc6b0c8fe7bf0
4
+ data.tar.gz: 37116b8077c2e96418351ddc3fa87058b1ca8d1846039e74fb1a86ba444518c6
5
+ SHA512:
6
+ metadata.gz: fba43d8df0a90410ae0d78c1afff9ca525c2f674aaaffb215db11eb365efb99f944323f7cb97846c1102f5c3c1153e2e3af11667bafe2563d43436534512448e
7
+ data.tar.gz: e70d253855608257ab9b4bcf354d70421ae35c8cc163e04ad902f7856817664f0780bf7ad7a37d9a475fbca0eb78279ac376ab944e42669c6aae0919b1cba1c1
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
@@ -0,0 +1 @@
1
+ ./tmp/gemset
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,24 @@
1
+
2
+ AllCops:
3
+ TargetRubyVersion: 2.5
4
+
5
+ Metrics/BlockLength:
6
+ Max: 300
7
+ Include:
8
+ - 'spec/**/*_spec.rb'
9
+
10
+ Metrics/ModuleLength:
11
+ Max: 300
12
+ Include:
13
+ - 'spec/**/*_spec.rb'
14
+
15
+ Style/CommentedKeyword:
16
+ Enabled: false
17
+
18
+ # This silences 'Missing top-level class documentation comment.', which we
19
+ # particularly want to do on (initially-)generated files.
20
+ Style/Documentation:
21
+ Enabled: false
22
+ Include:
23
+ - 'apps/**/*.rb'
24
+ - 'lib/**/*.rb'
@@ -0,0 +1 @@
1
+ 2.5.0
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
4
+ - 2.2.1
5
+ - jruby-9.0.0.0.pre1
6
+ # - rbx
7
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in repository-support.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Jeff Dickey
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,204 @@
1
+ <h1>Repository::Support</h1>
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/repository-support.svg)](http://badge.fury.io/rb/repository-support)
4
+ [![Code Climate](https://codeclimate.com/github/jdickey/repository-support/badges/gpa.svg)](https://codeclimate.com/github/jdickey/repository-support)
5
+ [ ![Codeship Status for jdickey/repository-support](https://codeship.com/projects/224d6180-997e-0132-c9c3-165733f17d49/status?branch=master)](https://codeship.com/projects/63652)
6
+ [![security](https://hakiri.io/github/jdickey/repository-support/master.svg)](https://hakiri.io/github/jdickey/repository-support/master)
7
+ [![Dependency Status](https://gemnasium.com/jdickey/repository-support.svg)](https://gemnasium.com/jdickey/repository-support)
8
+
9
+ <h2>Contents</h2>
10
+
11
+ - [Overview](#overview)
12
+ - [IMPORTANT LEGACY NOTICE](#important-legacy-notice)
13
+ - [Installation](#installation)
14
+ - [Usage](#usage)
15
+ * [`StoreResult`](#storeresult)
16
+ + [`StoreResult::Success`](#storeresultsuccess)
17
+ + [`StoreResult::Failure`](#storeresultfailure)
18
+ * [`ErrorFactory`](#errorfactory)
19
+ * [`TestAttributeContainer`](#testattributecontainer)
20
+ * [A Note on Parameters](#a-note-on-parameters)
21
+ - [Contributing](#contributing)
22
+ - [Version History](#version-history)
23
+ - [Legal](#legal)
24
+
25
+ ## Overview
26
+
27
+ This Gem provides several support classes and modules for
28
+ [`Repository::Base`](https://github.com/jdickey/repository-base) and its
29
+ user-created subclasses, which implement the Repository layer of a typical Data
30
+ Mapper pattern architecture.
31
+
32
+ These classes and modules are:
33
+
34
+ * `ErrorFactory` provides a single class method, `.create` which, when supplied with an `ActiveModel::Errors`-quacking object as a parameter, produces an Array of Hashes containing JSON-compatible error information;
35
+ * `ResultBuilder` is a Command-pattern class whose `#initialize` method takes one parameter and whose `#build` method evaluates that value. If it is truthy, then `#build` returns a `StoreResult::Success` (see below) with that value as its "paylaaod". If the value is falsy, then `#build` returns a `StoreResult#Failure`, yielding the value to a block that returns the payload for the `StoreResult`.
36
+ * `StoreResult` is a simple value object with three accessors for values passed in to the `#initialize` method: namely `#entity` (some value object); `#success` (a Boolean, aliased as `#success?`); and `#errors` an Array of error records as created by `ErrorFactory.create`. It has two subclasses: `StoreResult::Success` fills in a `StoreResult` using its single parameter (the entity) and defaults for the other fields; and `StoreResult::Failure`, which does likewise initialised with an array of error hashes.
37
+ * `TestAttributeContainer` is a module that, when used to extend a class, adds an `attributes` Hash property (reader and writer) to the extending class. While `attributes` is initially empty, it may be added to either by defining a single key, or by mass-assigning a Hash to `attributes`. 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.
38
+
39
+ ## IMPORTANT LEGACY NOTICE
40
+
41
+ **_NOTICE!_** 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.
42
+
43
+ As such, it has been superseded and far outshone by other, team efforts, notably [ROM](http://rom-rb.org/) as used with [Hanami](http://hanamirb.org/) and [Trailblazer](http://trailblazer.to/). You are *strongly advised* to examine these and other tools rather than to use this for *any* new development. The Gem is being republished as an 0.1.0 release purely for internal archaeologigical purposes.
44
+
45
+ ## Installation
46
+
47
+ Add this line to your application's Gemfile:
48
+
49
+ ```ruby
50
+ gem 'repository-support'
51
+ ```
52
+
53
+ And then execute:
54
+
55
+ $ bundle
56
+
57
+ Or install it yourself as:
58
+
59
+ $ gem install repository-support
60
+
61
+ ## Usage
62
+
63
+ ### `StoreResult`
64
+
65
+ `StoreReult` is used as the return value from all `Repository::Base` instance
66
+ methods (actions) *except* `#all`.
67
+
68
+ If the action implemented by the method was successful, it returns a
69
+ `StoreResult` where
70
+
71
+ * the `entity` attribute is an entity matching the state of the record persisted or accessed by the action;
72
+ * the `success` attribute (or `#success?` method) is `true`; and
73
+ * the `errors` attribute is an empty Array.
74
+
75
+ If the action was unsuccessful, the repository method returns a `StoreResult`
76
+ where
77
+
78
+ * the `entity` attribute is `nil`;
79
+ * the `success` attribute (or `#success?` method) is `false`; and
80
+ * the `errors` attribute contains one error Hash for each error preventing the action from succeeding.
81
+
82
+ #### `StoreResult::Success`
83
+
84
+ This subclass of `StoreResult` is a convenience for initialising a successful
85
+ `StoreResult`. Its `#initialize` method takes a single parameter, the entity to
86
+ be used in the result, with the other fields set as described above for a
87
+ successful result.
88
+
89
+ #### `StoreResult::Failure`
90
+
91
+ This subclass of `StoreResult` is a convenience for initialising an unsuccessful
92
+ `StoreResult`. Its `#initialize` method takes a single parameter, the Array of
93
+ error hashes to be used in the result, with the other fields set as described
94
+ above for an unsuccessful result.
95
+
96
+ ### `ErrorFactory`
97
+
98
+ This class has a single class method, `.create`. Given a parameter value that
99
+ quacks as an[`ActiveModel::Errors`](http://api.rubyonrails.org/classes/ActiveModel/Errors.html)
100
+ instance, it returns an Array where each item is a Hash derived from each error
101
+ reported by the parameter object, or an empty Array if there are no errors. Each
102
+ Hash in the Array has two fields:
103
+
104
+ 1. `field`, which contains the attribute passed to [`ActiveModel::Errors#add`](http://api.rubyonrails.org/classes/ActiveModel/Errors.html#method-i-add) *as a string*; and
105
+ 1. `message`, which contains the message as passed into the same `#add` call.
106
+
107
+ So, given an `ActiveModel::Errors` object that resulted from the following code:
108
+
109
+ ```ruby
110
+ errors = ActiveModel::Errors.new self
111
+ # ...
112
+ errors.add :frobulator, 'does not frob'
113
+ errors.add :frobulator, `is busted'
114
+ errors.add :foo, 'is :foo'
115
+ # ...
116
+ error_data = ErrorFactory.create errors
117
+ @logger.log error_data
118
+ ```
119
+
120
+ the value of `error_data` written to the log would be (formatted for clarity)
121
+
122
+ ```
123
+ [
124
+ {field: 'frobulator', message: 'does not frob'},
125
+ {field: 'frobulator', message: 'is busted'},
126
+ {field: 'foo', 'is :foo'}
127
+ ]
128
+ ```
129
+
130
+ Note that no guarantees are made for ordering, just as seems to be the case for
131
+ `ActiveModel::Errors`.
132
+
133
+ ### `TestAttributeContainer`
134
+
135
+ This module implements support for attributes in a way that can be thought of as "halfway between a [`Struct`](http://ruby-doc.org//core-2.1.5/Struct.html) and an [`OpenStruct`](http://ruby-doc.org/stdlib-2.1.5/libdoc/ostruct/rdoc/OpenStruct.html) or [`FancyOpenStruct`](https://github.com/tomchapin/fancy-open-struct/)."
136
+
137
+ By extending a class with the module and invoking the `init_empty_attribute_container` class method within that class, a Hash is added as the `attributes` attribute of each instance of that class. It can be assigned to directly; once having done so, individual "attributes" may be accessed *or modified* through a method call using the name of the attribute.
138
+
139
+ For example:
140
+
141
+ ```ruby
142
+ class Foo
143
+ extend Repository::Support::TestAttributeContainer
144
+
145
+ init_empty_attribute_container
146
+ end
147
+
148
+ # interactively
149
+ foo = Foo.new
150
+ # => #<Foo:0x007fd2b4b9da28>
151
+ foo.attributes
152
+ # => {}
153
+ foo.attributes = { foo: true, bar: 42 }
154
+ # => {:foo=>true, :bar=>42}
155
+ foo.foo
156
+ # => true
157
+ foo.foo = :whatever_you_want
158
+ # => :whatever_you_want
159
+ foo.attributes
160
+ # => {:foo=>:whatever_you_want, :bar=>42}
161
+ foo.quux
162
+ # => NoMethodError: undefined method `quux' # ...
163
+ foo.attributes[:quux] = 'hello'
164
+ # => "hello"
165
+ foo.quux
166
+ # => "hello"
167
+ ```
168
+
169
+ To create a new attribute after the container has been set up, assign to a new key in the `attributes` 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 `attributes`, however, undefined methods raise errors as usual.
170
+
171
+ ### A Note on Parameters
172
+
173
+ All *public* methods having multiple arguments (including `#initialize`) in each
174
+ of the classes defined above use the keyword-argument specification introduced
175
+ in Ruby 2.0. By removing order dependency of arguments, inadvertent-reordering
176
+ errors are no longer a
177
+ [hunt-the-typo](http://en.wikipedia.org/wiki/Hunt_the_Wumpus)
178
+ exercise. This rule *does not* apply to single-parameter methods, nor to
179
+ `private` methods.
180
+
181
+ ## Contributing
182
+
183
+ 1. Fork it ( https://github.com/jdickey/repository-support/fork )
184
+ 1. Create your feature branch (`git checkout -b my-new-feature`)
185
+ 1. Ensure that your changes are completely covered by *passing* specs, and comply with the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) as enforced by [RuboCop](https://github.com/bbatsov/rubocop). To verify this, run `bundle exec rake`, noting and repairing any lapses in coverage or style violations;
186
+ 1. Commit your changes (`git commit -a`). Please *do not* use a single-line commit message (`git commit -am "some message"`). 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;
187
+ 1. Push to the branch (`git push origin my-new-feature`)
188
+ 1. 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. *If this is a modification to existing code, reference the open issue being addressed*.
189
+ 1. Don't be discouraged if the PR generates a discussion that leads to further refinement of your PR through additional commits. These should *generally* be discussed in comments on the PR itself; discussion in the Gitter room (see below) may also be useful;
190
+ 1. If you've comments, questions, or just want to talk through your ideas, don't hesitate to hang out in the `Repository::Base` [room on Gitter](https://gitter.im/jdickey/repository-base). Ask away!
191
+
192
+ ## Version History
193
+
194
+ | Version | Date | Notes |
195
+ | ------- | ---- | ----- |
196
+ | v0.1.0 | 2 February 2018 | Changed MRI supported version from 2.2.2 to 2.5.0; **published legacy notice** |
197
+ | v0.0.4 | 9 March 2015 | Added experimental, one-off JRuby 9000 support |
198
+ | v0.0.3 | 21 February 2015 | Completed initial feature development |
199
+ | v0.0.2 | 18 February 2015 | Internal; incremental feature development |
200
+ | v0.0.1 | 18 February 2015 | Internal; incremental feature development |
201
+
202
+ ## Legal
203
+
204
+ This document and the accompanying code are Copyright &copy; 2015-2018 by Jeff Dickey/Seven Sigma Agility, and are released under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,20 @@
1
+
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
5
+
6
+ RuboCop::RakeTask.new(:rubocop) do |task|
7
+ task.patterns = [
8
+ 'lib/**/*.rb',
9
+ 'spec/spec_helper.rb',
10
+ 'spec/**/*_spec.rb'
11
+ ]
12
+ task.formatters = ['simple', 'd']
13
+ task.fail_on_error = true
14
+ task.options << '--rails'
15
+ end
16
+
17
+ RSpec::Core::RakeTask.new :spec
18
+
19
+ task(:default).clear
20
+ task default: [:spec, :rubocop]
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1 || ">= 0.a"
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||= begin
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version || "#{Gem::Requirement.default}.a"
67
+ end
68
+ end
69
+
70
+ def load_bundler!
71
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
72
+
73
+ # must dup string for RG < 1.8 compatibility
74
+ activate_bundler(bundler_version.dup)
75
+ end
76
+
77
+ def activate_bundler(bundler_version)
78
+ if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
79
+ bundler_version = "< 2"
80
+ end
81
+ gem_error = activation_error_handling do
82
+ gem "bundler", bundler_version
83
+ end
84
+ return if gem_error.nil?
85
+ require_error = activation_error_handling do
86
+ require "bundler/version"
87
+ end
88
+ return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89
+ warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
90
+ exit 42
91
+ end
92
+
93
+ def activation_error_handling
94
+ yield
95
+ nil
96
+ rescue StandardError, LoadError => e
97
+ e
98
+ end
99
+ end
100
+
101
+ m.load_bundler!
102
+
103
+ if m.invoked_as_script?
104
+ load Gem.bin_path("bundler", "bundle")
105
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'bundler' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('bundler', 'bundler')
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'htmldiff' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("diff-lcs", "htmldiff")