declarative-builder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8a7a21a5da3c82bf9edcbfc53a0b493e3c886ad0
4
+ data.tar.gz: 62bb129cb86b262e81792e59bb83ec841ec8df7e
5
+ SHA512:
6
+ metadata.gz: 574cc0bb1eb623eb61c57b84d156470e400f864f4fc840a1c391826191399f4716a136c4e84de11f666c63397d8217447360efe1d5198c4202e1a5dd69b11e57
7
+ data.tar.gz: 67a36117a847c5069ac2131eadcb75e9a1116ae1e59a486df79917934dcbbe945b4af59bc8f32b348c9451fd0ee5b0212ed24cd7ecb1d2c869a85b75a6a59f8d
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,10 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ - 2.1
5
+ - 2.2
6
+ - 2.3.1
7
+ - jruby-19mode
8
+ - jruby
9
+ before_install:
10
+ - gem install bundler
@@ -0,0 +1,3 @@
1
+ # 0.1.0
2
+
3
+ * Introduce `Declarative::Builder` as a replacement for `Uber::Builder`.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in uber.gemspec
4
+ gemspec
5
+
6
+ gem "minitest-line"
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Nick Sutterer
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,355 @@
1
+ # Uber
2
+
3
+ _Gem-authoring tools like class method inheritance in modules, dynamic options and more._
4
+
5
+ ## Installation
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/uber.svg)](http://badge.fury.io/rb/uber)
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'uber'
13
+ ```
14
+
15
+ Uber runs with Ruby >= 1.9.3.
16
+
17
+ # Inheritable Class Attributes
18
+
19
+ If you want inherited class attributes, this is for you.
20
+ This is a mandatory mechanism for creating DSLs.
21
+
22
+ ```ruby
23
+ require 'uber/inheritable_attr'
24
+
25
+ class Song
26
+ extend Uber::InheritableAttr
27
+
28
+ inheritable_attr :properties
29
+ self.properties = [:title, :track] # initialize it before using it.
30
+ end
31
+ ```
32
+
33
+ Note that you have to initialize your class attribute with whatever you want - usually a hash or an array.
34
+
35
+ ```ruby
36
+ Song.properties #=> [:title, :track]
37
+ ```
38
+
39
+ A subclass of `Song` will have a `clone`d `properties` class attribute.
40
+
41
+ ```ruby
42
+ class Hit < Song
43
+ end
44
+
45
+ Hit.properties #=> [:title, :track]
46
+ ```
47
+
48
+ The cool thing about the inheritance is: you can work on the inherited attribute without any restrictions. It is a _copy_ of the original.
49
+
50
+ ```ruby
51
+ Hit.properties << :number
52
+
53
+ Hit.properties #=> [:title, :track, :number]
54
+ Song.properties #=> [:title, :track]
55
+ ```
56
+
57
+ It's similar to ActiveSupport's `class_attribute` but with a simpler implementation.
58
+ It is less dangerous. There are no restrictions for modifying the attribute. [compared to `class_attribute`](http://apidock.com/rails/v4.0.2/Class/class_attribute).
59
+
60
+ ## Uncloneable Values
61
+
62
+ `::inheritable_attr` will `clone` values to copy them to subclasses. Uber won't attempt to clone `Symbol`, `nil`, `true` and `false` per default.
63
+
64
+ If you assign any other unclonable value you need to tell Uber that.
65
+
66
+ ```ruby
67
+ class Song
68
+ extend Uber::InheritableAttr
69
+ inheritable_attr :properties, clone: false
70
+ ```
71
+
72
+ This won't `clone` but simply pass the value on to the subclass.
73
+
74
+
75
+ # Dynamic Options
76
+
77
+ Implements the pattern of defining configuration options and dynamically evaluating them at run-time.
78
+
79
+ Usually DSL methods accept a number of options that can either be static values, symbolized instance method names, or blocks (lambdas/Procs).
80
+
81
+ Here's an example from Cells.
82
+
83
+ ```ruby
84
+ cache :show, tags: lambda { Tag.last }, expires_in: 5.mins, ttl: :time_to_live
85
+ ```
86
+
87
+ Usually, when processing these options, you'd have to check every option for its type, evaluate the `tags:` lambda in a particular context, call the `#time_to_live` instance method, etc.
88
+
89
+ This is abstracted in `Uber::Options` and could be implemented like this.
90
+
91
+ ```ruby
92
+ require 'uber/options'
93
+
94
+ options = Uber::Options.new(tags: lambda { Tag.last },
95
+ expires_in: 5.mins,
96
+ ttl: :time_to_live)
97
+ ```
98
+
99
+ Just initialize `Options` with your actual options hash. While this usually happens on class level at compile-time, evaluating the hash happens at run-time.
100
+
101
+ ```ruby
102
+ class User < ActiveRecord::Base # this could be any Ruby class.
103
+ # .. lots of code
104
+
105
+ def time_to_live(*args)
106
+ "n/a"
107
+ end
108
+ end
109
+
110
+ user = User.find(1)
111
+
112
+ options.evaluate(user, *args) #=> {tags: "hot", expires_in: 300, ttl: "n/a"}
113
+ ```
114
+
115
+ ## Evaluating Dynamic Options
116
+
117
+ To evaluate the options to a real hash, the following happens:
118
+
119
+ * The `tags:` lambda is executed in `user` context (using `instance_exec`). This allows accessing instance variables or calling instance methods.
120
+ * Nothing is done with `expires_in`'s value, it is static.
121
+ * `user.time_to_live?` is called as the symbol `:time_to_live` indicates that this is an instance method.
122
+
123
+ The default behaviour is to treat `Proc`s, lambdas and symbolized `:method` names as dynamic options, everything else is considered static. Optional arguments from the `evaluate` call are passed in either as block or method arguments for dynamic options.
124
+
125
+ This is a pattern well-known from Rails and other frameworks.
126
+
127
+ ## Uber::Callable
128
+
129
+ A third way of providing a dynamic option is using a "callable" object. This saves you the unreadable lambda syntax and gives you more flexibility.
130
+
131
+ ```ruby
132
+ require 'uber/callable'
133
+ class Tags
134
+ include Uber::Callable
135
+
136
+ def call(context, *args)
137
+ [:comment]
138
+ end
139
+ end
140
+ ```
141
+
142
+ By including `Uber::Callable`, uber will invoke the `#call` method on the specified object.
143
+
144
+ Note how you simply pass an instance of the callable object into the hash instead of a lambda.
145
+
146
+ ```ruby
147
+ options = Uber::Options.new(tags: Tags.new)
148
+ ```
149
+
150
+ ## Option
151
+
152
+ `Uber::Option` implements the pattern of taking an option, such as a proc, instance method name, or static value, and evaluate it at runtime without knowing the option's implementation.
153
+
154
+ Creating `Option` instances via `::[]` usually happens on class-level in DSL methods.
155
+
156
+ ```ruby
157
+ with_proc = Uber::Option[ ->(options) { "proc: #{options.inspect}" } ]
158
+ with_static = Uber::Option[ "Static value" ]
159
+ with_method = Uber::Option[ :name_of_method ]
160
+
161
+ def name_of_method(options)
162
+ "method: #{options.inspect}"
163
+ end
164
+ ```
165
+
166
+ Use `#call` to evaluate the options at runtime.
167
+
168
+ ```ruby
169
+ with_proc.(1, 2) #=> "proc: [1, 2]"
170
+ with_static.(1, 2) #=> "Static value" # arguments are ignored
171
+ with_method.(self, 1, 2) #=> "method: [1, 2]" # first arg is context
172
+ ```
173
+
174
+ It's also possible to evaluate a callable object. It has to be marked with `Uber::Callable` beforehand.
175
+
176
+ ```ruby
177
+ class MyCallable
178
+ include Uber::Callable
179
+
180
+ def call(context, *args)
181
+ "callable: #{args.inspect}, #{context}"
182
+ end
183
+ end
184
+
185
+ with_callable = Uber::Option[ MyCallable.new ]
186
+ ```
187
+
188
+ The context is passed as first argument.
189
+
190
+ ```ruby
191
+ with_callable.(Object, 1, 2) #=> "callable: [1, 2] Object"
192
+ ```
193
+
194
+ You can also make blocks being `instance_exec`ed on the context, giving a unique API to all option types.
195
+
196
+ ```ruby
197
+ with_instance_proc = Uber::Option[ ->(options) { "proc: #{options.inspect} #{self}" }, instance_exec: true ]
198
+ ```
199
+
200
+ The first argument now becomes the context, exactly the way it works for the method and callable type.
201
+
202
+ ```ruby
203
+ with_instance_proc.(Object, 1, 2) #=> "proc [1, 2] Object"
204
+ ```
205
+
206
+
207
+ # Delegates
208
+
209
+ Using `::delegates` works exactly like the `Forwardable` module in Ruby, with one bonus: It creates the accessors in a module, allowing you to override and call `super` in a user module or class.
210
+
211
+ ```ruby
212
+ require 'uber/delegates'
213
+
214
+ class SongDecorator
215
+ def initialize(song)
216
+ @song = song
217
+ end
218
+ attr_reader :song
219
+
220
+ extend Uber::Delegates
221
+
222
+ delegates :song, :title, :id # delegate :title and :id to #song.
223
+
224
+ def title
225
+ super.downcase # this calls the original delegate #title.
226
+ end
227
+ end
228
+ ```
229
+
230
+ This creates readers `#title` and `#id` which are delegated to `#song`.
231
+
232
+ ```ruby
233
+ song = SongDecorator.new(Song.create(id: 1, title: "HELLOWEEN!"))
234
+
235
+ song.id #=> 1
236
+ song.title #=> "helloween!"
237
+ ```
238
+
239
+ Note how `#title` calls the original title and then downcases the string.
240
+
241
+ # Builder
242
+
243
+ Builders are good for polymorphically creating objects without having to know where that happens. You define a builder with conditions in one class, and that class takes care of creating the actual desired class.
244
+
245
+ ## Declarative Interface
246
+
247
+ Include `Uber::Builder` to leverage the `::builds` method for adding builders, and `::build!` to run those builders in a given context and with arbitrary options.
248
+
249
+
250
+ ```ruby
251
+ require "uber/builder"
252
+
253
+ class User
254
+ include Uber::Builder
255
+
256
+ builds do |options|
257
+ Admin if params[:admin]
258
+ end
259
+ end
260
+
261
+ class Admin
262
+ end
263
+ ```
264
+
265
+ Note that you can call `builds` as many times as you want per class.
266
+
267
+ Run the builders using `::build!`.
268
+
269
+ ```ruby
270
+ User.build!(User, {}) #=> User
271
+ User.build!(User, { admin: true }) #=> Admin
272
+ ```
273
+ The first argument is the context in which the builder blocks will be executed. This is also the default return value if all builders returned a falsey value.
274
+
275
+ All following arguments will be passed straight through to the procs.
276
+
277
+ Your API should communicate `User` as the only public class, since the builder hides details about computing the concrete class.
278
+
279
+ ### Builder: Procs
280
+
281
+ You may also use procs instead of blocks.
282
+
283
+ ```ruby
284
+ class User
285
+ include Uber::Builder
286
+
287
+ builds ->(options) do
288
+ return SignedIn if params[:current_user]
289
+ return Admin if params[:admin]
290
+ Anonymous
291
+ end
292
+ end
293
+ ```
294
+
295
+ Note that this allows `return`s in the block.
296
+
297
+ ## Builder: Direct API
298
+
299
+ In case you don't want the `builds` DSL, you can instantiate a `Builders` object yourself and add builders to it using `#<<`.
300
+
301
+ ```ruby
302
+ MyBuilders = Uber::Builder::Builders.new
303
+ MyBuilders << ->(options) do
304
+ return Admin if options[:admin]
305
+ end
306
+ ```
307
+
308
+ Note that you can call `Builders#<<` multiple times per instance.
309
+
310
+ Invoke the builder using `#call`.
311
+
312
+ ```ruby
313
+ MyBuilders.call(User, {}) #=> User
314
+ MyBuilders.call(User, { admin: true }) #=> Admin
315
+ ```
316
+
317
+ Again, the first object is the context/default return value, all other arguments are passed to the builder procs.
318
+
319
+ ## Builder: Contexts
320
+
321
+ Every proc is `instance_exec`ed in the context you pass into `build!` (or `call`), allowing you to define generic, shareable builders.
322
+
323
+ ```ruby
324
+ MyBuilders = Uber::Builder::Builders.new
325
+ MyBuilders << ->(options) do
326
+ return self::Admin if options[:admin] # note the self:: !
327
+ end
328
+
329
+ class User
330
+ class Admin
331
+ end
332
+ end
333
+
334
+ class Instructor
335
+ class Admin
336
+ end
337
+ end
338
+ ```
339
+
340
+ Now, depending on the context class, the builder will return different classes.
341
+
342
+ ```ruby
343
+ MyBuilders.call(User, {}) #=> User
344
+ MyBuilders.call(User, { admin: true }) #=> User::Admin
345
+ MyBuilders.call(Instructor, {}) #=> Instructor
346
+ MyBuilders.call(Instructor, { admin: true }) #=> Instructor::Admin
347
+ ```
348
+
349
+ Don't forget the `self::` when writing generic builders, and write tests.
350
+
351
+ # License
352
+
353
+ Copyright (c) 2014 by Nick Sutterer <apotonick@gmail.com>
354
+
355
+ Uber is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+
6
+ desc 'Test the representable gem.'
7
+ task :default => :test
8
+
9
+ Rake::TestTask.new(:test) do |test|
10
+ test.libs << 'test'
11
+ test.test_files = FileList['test/*_test.rb']
12
+ test.verbose = true
13
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../lib/declarative/builder/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Nick Sutterer"]
5
+ gem.email = ["apotonick@gmail.com"]
6
+ gem.description = %q{Generic builder pattern.}
7
+ gem.summary = %q{Generic builder pattern.}
8
+ gem.homepage = "https://github.com/apotonick/declarative-builder"
9
+ gem.license = "MIT"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "declarative-builder"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Declarative::Builder::VERSION
17
+
18
+ gem.add_dependency "declarative-option", "< 0.2.0"
19
+
20
+ gem.add_development_dependency "rake"
21
+ gem.add_development_dependency "minitest"
22
+ end
@@ -0,0 +1 @@
1
+ require "declarative/builder"
@@ -0,0 +1,44 @@
1
+ require "declarative/option"
2
+
3
+ module Declarative
4
+ module Builder
5
+ def self.included(base)
6
+ base.extend DSL
7
+ base.extend Build
8
+ end
9
+
10
+ class Builders < Array
11
+ def call(context, *args)
12
+ each do |block|
13
+ klass = block.(context, *args) and return klass # Declarative::Option#call()
14
+ end
15
+
16
+ context
17
+ end
18
+
19
+ def <<(proc)
20
+ super Declarative::Option( proc, instance_exec: true ) # lambdas are always instance_exec'ed.
21
+ end
22
+ end
23
+
24
+ module DSL
25
+ def builders
26
+ @builders ||= Builders.new
27
+ end
28
+
29
+ def builds(proc=nil, &block)
30
+ builders << (proc || block)
31
+ end
32
+ end
33
+
34
+ module Build
35
+ # Call this from your class to compute the concrete target class.
36
+ def build!(context, *args)
37
+ builders.(context, *args)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+
44
+ # Declarative::Builder(->(options) { options[:current_user] ? Bla : Blubb })
@@ -0,0 +1,5 @@
1
+ module Declarative
2
+ module Builder
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,147 @@
1
+ require "test_helper"
2
+ require "declarative/builder"
3
+
4
+ class BuilderTest < MiniTest::Spec
5
+ Evergreen = Struct.new(:title)
6
+ Hit = Struct.new(:title)
7
+
8
+ class Song
9
+ include Declarative::Builder
10
+
11
+ builds do |options|
12
+ if options[:evergreen]
13
+ Evergreen
14
+ elsif options[:hit]
15
+ Hit
16
+ end
17
+ end
18
+
19
+ def self.build(options)
20
+ build!(self, options).new
21
+ end
22
+ end
23
+
24
+ # building class if no block matches
25
+ it { Song.build({}).must_be_instance_of Song }
26
+
27
+ it { Song.build({evergreen: true}).must_be_instance_of Evergreen }
28
+ it { Song.build({hit: true}).must_be_instance_of Hit }
29
+
30
+ # test chained builds.
31
+ class Track
32
+ include Declarative::Builder
33
+
34
+ builds do |options|
35
+ Evergreen if options[:evergreen]
36
+ end
37
+
38
+ builds do |options|
39
+ Hit if options[:hit]
40
+ end
41
+
42
+ def self.build(options)
43
+ build!(self, options).new
44
+ end
45
+ end
46
+
47
+ it { Track.build({}).must_be_instance_of Track }
48
+ it { Track.build({evergreen: true}).must_be_instance_of Evergreen }
49
+ it { Track.build({hit: true}).must_be_instance_of Hit }
50
+
51
+
52
+ # test inheritance. builder do not inherit.
53
+ class Play < Song
54
+ end
55
+
56
+ it { Play.build({}).must_be_instance_of Play }
57
+ it { Play.build({evergreen: true}).must_be_instance_of Play }
58
+ it { Play.build({hit: true}).must_be_instance_of Play }
59
+
60
+ # test return from builds
61
+ class Boomerang
62
+ include Declarative::Builder
63
+
64
+ builds ->(options) do
65
+ return Song if options[:hit]
66
+ end
67
+
68
+ def self.build(options)
69
+ build!(self, options).new
70
+ end
71
+ end
72
+
73
+ it { Boomerang.build({}).must_be_instance_of Boomerang }
74
+ it { Boomerang.build({hit: true}).must_be_instance_of Song }
75
+ end
76
+
77
+
78
+ class BuilderScopeTest < MiniTest::Spec
79
+ def self.builder_method(options)
80
+ options[:from_builder_method] and return self
81
+ end
82
+
83
+ class Hit; end
84
+
85
+ class Song
86
+ class Hit
87
+ end
88
+
89
+ include Declarative::Builder
90
+
91
+ builds :builder_method # i get called first.
92
+ builds ->(options) do # and i second.
93
+ self::Hit
94
+ end
95
+
96
+ def self.build(context, options={})
97
+ build!(context, options)
98
+ end
99
+ end
100
+
101
+ it do
102
+ Song.build(self.class).must_equal BuilderScopeTest::Hit
103
+
104
+ # this runs BuilderScopeTest::builder_method and returns self.
105
+ Song.build(self.class, from_builder_method: true).must_equal BuilderScopeTest
106
+ end
107
+
108
+ class Evergreen
109
+ class Hit
110
+ end
111
+
112
+ include Declarative::Builder
113
+
114
+ class << self
115
+ attr_writer :builders
116
+ end
117
+ self.builders = Song.builders
118
+
119
+ def self.build(context, options={})
120
+ build!(context, options)
121
+ end
122
+
123
+ def self.builder_method(options)
124
+ options[:from_builder_method] and return self
125
+ end
126
+ end
127
+
128
+ it do
129
+ # running the "copied" block in Evergreen will reference the correct @context.
130
+ Evergreen.build(Evergreen).must_equal BuilderScopeTest::Evergreen::Hit
131
+
132
+ Evergreen.build(Evergreen, from_builder_method: true).must_equal BuilderScopeTest::Evergreen
133
+ end
134
+
135
+ #---
136
+ # Builders API
137
+ # Builders#call
138
+ # Builders#<<
139
+ A = Class.new
140
+ MyBuilders = Declarative::Builder::Builders.new
141
+ MyBuilders << ->(options) do
142
+ return Song if options[:hit]
143
+ end
144
+
145
+ it { MyBuilders.call(A, {}).new.must_be_instance_of A }
146
+ it { MyBuilders.call(A, { hit: true }).new.must_be_instance_of Song }
147
+ end
@@ -0,0 +1 @@
1
+ require "minitest/autorun"
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: declarative-builder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick Sutterer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: declarative-option
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "<"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "<"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Generic builder pattern.
56
+ email:
57
+ - apotonick@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".travis.yml"
64
+ - CHANGES.md
65
+ - Gemfile
66
+ - LICENSE
67
+ - README.md
68
+ - Rakefile
69
+ - declarative-builder.gemspec
70
+ - lib/declarative-builder.rb
71
+ - lib/declarative/builder.rb
72
+ - lib/declarative/builder/version.rb
73
+ - test/builder_test.rb
74
+ - test/test_helper.rb
75
+ homepage: https://github.com/apotonick/declarative-builder
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.6.3
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Generic builder pattern.
99
+ test_files:
100
+ - test/builder_test.rb
101
+ - test/test_helper.rb