building_blocks 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a8b00f6d31a66e4ee00c4617a1ea5542407a060d
4
+ data.tar.gz: d68f14603537f03ce13da0d30ccc642e5354153e
5
+ SHA512:
6
+ metadata.gz: 96a5948aa3fe772601b35ecbea6bcdbfcda56ebe8d0895a21a486077c04d808c2918fdc92a8199ec95854d2685e47cfe526198967c7a68a37c6e08e8bcf9415f
7
+ data.tar.gz: d7f7ec68e9dc53d0b60c913f54489326db92ac8eb16660aa3285839207523429f2158acce609c2d4ce27d5af928ddf9bfa13e52735d53da03dddb6581bef8a14
data/.gitignore ADDED
@@ -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
data/.travis.yml ADDED
@@ -0,0 +1,22 @@
1
+ branches:
2
+ only:
3
+ - master
4
+
5
+ before_install:
6
+ - env
7
+
8
+ before_script:
9
+ - bundle exec rake
10
+
11
+ bundler_args: --without doc
12
+
13
+ cache:
14
+ - apt
15
+ - bundler
16
+
17
+ language: ruby
18
+
19
+ rvm:
20
+ - 1.9.3
21
+ - 2.0.0
22
+ - 2.1.1
data/.yardopts ADDED
@@ -0,0 +1,7 @@
1
+ --output-dir doc/
2
+ --readme README.md
3
+ --title BuildingBlocks
4
+ --markup=markdown
5
+ --protected
6
+ --private
7
+ lib/**/*.rb
data/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :doc do
6
+ gem 'yard', require: false
7
+ end
8
+
9
+ group :test do
10
+ gem 'coveralls', :require => false
11
+ gem 'faker'
12
+ gem 'minitest'
13
+ gem 'mocha', :require => false
14
+ gem 'shoulda-context'
15
+ end
16
+
17
+ # Dev and test gems not needed for CI
18
+ unless ENV['CI']
19
+ group :development, :test do
20
+ gem 'guard'
21
+ gem 'guard-minitest'
22
+ gem 'pry-debugger', :platforms => :mri
23
+ end
24
+ end
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ guard :minitest do
2
+ ignore(%r{.*sw[pon]$})
3
+
4
+ watch(%r{^lib/building_blocks.rb}) { 'test' }
5
+ watch(%r{^lib/building_blocks/(.+)\.rb}) { |m| "test/unit/#{m[1]}_test.rb" }
6
+ watch(%r{^test/(?:.+/).+_test\.rb$})
7
+ watch('test/test_helper.rb') { 'test' }
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Interval Braining
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.
data/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # BuildingBlocks
2
+ [![Build Status](https://travis-ci.org/interval-braining/building_blocks.png)](https://travis-ci.org/interval-braining/building_blocks)
3
+ [![Coverage Status](https://coveralls.io/repos/interval-braining/building_blocks/badge.png)](https://coveralls.io/r/interval-braining/building_blocks)
4
+ [![Code Climate](https://codeclimate.com/github/interval-braining/building_blocks.png)](https://codeclimate.com/github/interval-braining/building_blocks)
5
+ [![Dependency Status](https://gemnasium.com/interval-braining/building_blocks.png)](https://gemnasium.com/interval-braining/building_blocks)
6
+
7
+ Simple DSL for defining Builder classes with customized DSLs.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'building_blocks'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install building_blocks
22
+
23
+ ## Usage
24
+
25
+ BuildingBlocks strives to make it easy to create customizable block-based DSLs
26
+ for building all variety of objects.
27
+
28
+ This is achieved through the use of Builder objects. At their core, Builders are
29
+ any object that defines a `build` method that takes in a block and returns an
30
+ Object. How that block is used and what Object is returned can depend greatly on
31
+ the Builder being used. In some cases the block could be ignored entirely. In
32
+ other cases the Object returned could be a JSON string. It all depends on the
33
+ Builder.
34
+
35
+ Because Builders are just Plain Old Ruby Objects, there are no restrictions on
36
+ how Builders can be defined or what they can accomplish during their build
37
+ process. However, since there are a few common patterns employed by most
38
+ Builders, BuildingBlocks offers a Buillder Builder that allows for defining
39
+ Builder objects using a simple DSL.
40
+
41
+ ### BuilderBuilder DSL
42
+ Though BuildingBlocks is not itself a Builder, it does implement a `build`
43
+ method that delegates all calls to the configured
44
+ `BuildingBlocks.default_builder`. By default the `default_builder` is configured
45
+ to use `BuildingBlocks::Builders::BuilderBuilder`, a sort of meta-Builder in that
46
+ it's a Builder that also happens to build other valid Builders.
47
+
48
+ ```ruby
49
+ # Creating a new builder class using the default builder DSL
50
+ Point = Struct.new(:x, :y)
51
+ PointBuilder = BuildingBlocks.build do
52
+ resource_class Point
53
+ attribute :x
54
+ attribute :y
55
+ end
56
+
57
+ # Creating a new Point instance using PointBuilder
58
+ # Both the block arg, builder, and self are the PointBuilder instance
59
+ point = PointBuilder.build do |builder|
60
+ x 1
61
+ y 1
62
+ end
63
+ # => #<struct Point x=1, y=1>
64
+
65
+
66
+ # A more complex example of the default builder DSL
67
+ class Circle
68
+ attr_accessor :radius
69
+ attr_reader :center
70
+
71
+ def center=(point)
72
+ raise ArgumentError, 'Bad point' unless point.is_a?(Point)
73
+ @center = point
74
+ end
75
+ end
76
+
77
+ CircleBuilder = BuildingBlocks.build do
78
+ resource_class Circle
79
+ attribute :radius
80
+ builder :center, :center=, PointBuilder
81
+ delegate :x, :x=, :center
82
+ delegate :y, :y=, :center
83
+ end
84
+
85
+ circle = CircleBuilder.build do |c|
86
+ radius 5
87
+ center do |m|
88
+ x 5
89
+ y 5
90
+ end
91
+
92
+ # Override the previously set value for y
93
+ y 1
94
+ end
95
+ # => #<Circle @center=#<struct Point x=5, y=1>, @radius=5>
96
+ ```
97
+
98
+ More information on the default builder definition DSL can be found in the
99
+ [docs](http://rubydoc.info/gems/building_blocks/0.0.1/frames)
100
+
101
+ ## Contributing
102
+
103
+ 1. Fork it ( https://github.com/interval-braining/building_blocks/fork )
104
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
105
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
106
+ 4. Push to the branch (`git push origin my-new-feature`)
107
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake.application.options.suppress_backtrace_pattern = /.*/
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.pattern = 'test/**/*_test.rb'
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'building_blocks/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'building_blocks'
8
+ spec.version = BuildingBlocks::VERSION
9
+ spec.authors = ['Danny Guinther']
10
+ spec.email = ['dannyguinther@gmail.com']
11
+ spec.summary = %q{Block-based Object Builders}
12
+ spec.description = %q{Simple DSL for defining block-based Object builders}
13
+ spec.homepage = 'https://github.com/interval-braining/building_blocks'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.test_files = spec.files.grep(%r{^test/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'bundler', '~> 1.5'
21
+ spec.add_development_dependency 'rake', '~> 0'
22
+ end
@@ -0,0 +1,59 @@
1
+ require 'forwardable'
2
+ require 'building_blocks/version'
3
+ require 'building_blocks/builders/builder_builder'
4
+
5
+ # Primary BuildingBlocks object providing an interface to build/define other
6
+ # builders using builders that build new builder objects.
7
+ module BuildingBlocks
8
+
9
+ class << self
10
+ extend Forwardable
11
+ def_delegator :default_builder, :build
12
+ end
13
+
14
+ # The default builder used for defining new builders when {build build}
15
+ # is invoked.
16
+ # @see build
17
+ # @see BuildingBlocks::Builders::BuilderBuilder
18
+ DEFAULT_DEFINITION_BUILDER = BuildingBlocks::Builders::BuilderBuilder
19
+
20
+ # Returns the object currently configured for use when defining new builders
21
+ # using {build build}. If a custom value has not been configured the
22
+ # {DEFAULT_DEFINITION_BUILDER default builder} is returned.
23
+ # @return [#build] The builder to be used for defining new builders when
24
+ # {build build} is invoked.
25
+ # @see build
26
+ # @see DEFAULT_DEFINITION_BUILDER
27
+ def self.default_builder
28
+ return @default_builder || DEFAULT_DEFINITION_BUILDER
29
+ end
30
+
31
+ # Sets the class that is used when defining new builders when using {build
32
+ # build} to the provided **builder**. If a value of `nil` or `false` is
33
+ # provided the {DEFAULT_DEFINITION_BUILDER default builder} will be
34
+ # used.
35
+ # @param [#build] builder The object to be used when defining new builders
36
+ # when using {build build}.
37
+ # @raise [ArgumentError] Raised if the object provided does not implement
38
+ # a #build method and is neither nil nor false.
39
+ # @return [#build] The builder argument provided is returned.
40
+ # @see DEFAULT_DEFINITION_BUILDER
41
+ # @see build
42
+ def self.default_builder=(builder)
43
+ if !!builder && !builder.respond_to?(:build)
44
+ raise ArgumentError, 'Expected object that responds to #build'
45
+ end
46
+ @default_builder = builder
47
+ end
48
+
49
+ # Namespace for builder classes
50
+ module Builders; end
51
+
52
+ # @!method self.build(*args, &block)
53
+ # Builds a new object using the the {default_builder default builder}. Any
54
+ # **args** or **block** provided are delegated directly to the `build` method
55
+ # of the {default_builder default builder}.
56
+ # @return [Object] The result of invoking `build` on the
57
+ # {#default_builder default builder}.
58
+ # @see default_builder
59
+ end
@@ -0,0 +1,341 @@
1
+ module BuildingBlocks
2
+ module Builders
3
+
4
+ # A builder that builds other builders using a minimal definition DSL.
5
+ # In brief, classes generated by this builder offer a number of built-in DSL
6
+ # macros that are used to describe how methods called against instances of
7
+ # the generated builder class are translated into actions to be taken on the
8
+ # {InstanceMethods#instance object instance} being built by the generated
9
+ # builder instance.
10
+ class BuilderBuilder
11
+
12
+ # Generates a new builder class with a number of built-in DSL methods used
13
+ # to describe how actions taken against instances of the builder class are
14
+ # translated into actions to be taken on the {InstanceMethods#instance
15
+ # object instance} being built. Further information on the available DSL
16
+ # methods can be found in {ClassInstanceMethods}.
17
+ # @return [Class] The generated builder class
18
+ # @see ClassInstanceMethods
19
+ def self.build
20
+ klass = Class.new
21
+ klass.extend(ClassInstanceMethods)
22
+ klass.send(:include, InstanceMethods)
23
+ klass.module_eval(&Proc.new) if block_given?
24
+ klass
25
+ end
26
+
27
+ # Methods available to classes generated by {BuilderBuilder
28
+ # BuilderBuilder}. Provides a generic, declarative DSL for describing
29
+ # custom builder classes.
30
+ module ClassInstanceMethods
31
+ include Forwardable
32
+
33
+ # The default means by which a new instance of the
34
+ # {ClassInstanceMethods#resource_class resource class} is initialized.
35
+ # @see {ClassInstanceMethods#initialize_with)
36
+ DEFAULT_INITIALIZE_WITH = lambda { |instance| resource_class.new }
37
+
38
+ # Declares a delegate method that will be available to instances of the
39
+ # generated builder class that describes a simple attribute that can be
40
+ # delegated directly to an existing method affiliated with the object
41
+ # instance being built.
42
+ #
43
+ # Though the underlying use of {delegate delegate} gives this method an
44
+ # enormous amount of potential power, the {attribute attribute} method
45
+ # is intended for use in fairly simple situations where delegation is
46
+ # required and the `attribute` descriptor provides some semantic value.
47
+ # More complex interactions should consider using the
48
+ # {delegate delegate} method directly to give library users some insight
49
+ # into the intention for more complex behavior.
50
+ # @param [String,Symbol] attr_name The name of the method that will be
51
+ # available to instances of the generated builder class that when
52
+ # invoked will trigger the **receiver_method** on the **receiver**.
53
+ # @param [String,Symbol] receiver_method The name of the method that
54
+ # should be invoked on the **receiver** object when the **attr_name**
55
+ # method is invoked. Defaults to a setter form of **attr_name**.
56
+ # @param [String,Symbol] receiver The object or method of the
57
+ # generated builder instance that should receive invocations of
58
+ # **receiver_method** when the **attr_name** method is called.
59
+ # Defaults to the {InstanceMethods#instance object instance} being
60
+ # built.
61
+ #
62
+ # If a String or Symbol value is provided for **receiver**, the value
63
+ # provided is resolved against the {InstanceMethods#instance object
64
+ # instance} being built at runtime to determine the appropriate
65
+ # receiver.
66
+ #
67
+ # For example if a value of :foo were provided for the receiver
68
+ # argument, at runtime, the receiver would be resolved to the object
69
+ # returned by invoking :foo on the {InstanceMethods#instance object
70
+ # instance} being built. Once resolved, the **receiver_method** would
71
+ # then be invoked on the receiver with any approprate arguments.
72
+ # @return [Symbol] The Symbol identifier form of **attr_name**
73
+ # identifying the method that will be available to instances of the
74
+ # generated builder class.
75
+ # @see #delegate
76
+ def attribute(attr_name, receiver_method = :"#{attr_name}=", receiver = nil)
77
+ delegate(attr_name, receiver_method, receiver)
78
+ return attr_name.to_sym
79
+ end
80
+
81
+ # By default, builds a new instance of the configured {#resource_class
82
+ # resource class}. This is achieved by evaluating the configured
83
+ # {#initialize_with} proc in the context of an instance of the generated
84
+ # builder class to generate a new object that will be used by the
85
+ # builder instance. If a block is given, the block is evaluated in the
86
+ # context of the builder instance after initialization.
87
+ # @param [Proc] block Optional block evaluated by the generated builder
88
+ # class instance after the {InstanceMethods#instance object instance}
89
+ # being built has been initialized.
90
+ # @return [Object] Returns the generated {InstanceMethods#instance
91
+ # object instance}.
92
+ # @see #initialize_with
93
+ def build
94
+ instance = instance_eval(&self.initialize_with)
95
+ builder = new(instance)
96
+ builder.instance_eval(&Proc.new) if block_given?
97
+ instance
98
+ end
99
+
100
+ # Declares a method, **attr_name**, available to instances of the
101
+ # generated builder class, that when called delegates to a
102
+ # **builder_class** to generate an object that is then passed to the
103
+ # **receiver_method** of the **receiver**.
104
+ #
105
+ # If a **builder_class** is given, the provided **builder_class** is
106
+ # used to generate the object for the receiver. If no **builder_class**
107
+ # is given and instead a **block** is provided, the given block is
108
+ # treated as an anonymous builder definition that is passed to
109
+ # {BuildingBlocks.build} to generate a new builder class that will be
110
+ # used later when **attr_name** is invoked on an instance of the
111
+ # generated builder class.
112
+ #
113
+ # See {InstanceMethods#example_builder_attr} for details of the method
114
+ # invoked when **attr_name** is called on an instance of the generated
115
+ # builder class.
116
+ #
117
+ # @param [String,Symbol] attr_name The name that will be used to define
118
+ # the method that will be available to instances of the generated
119
+ # builder class that when invoked will trigger the **builder_class**.
120
+ # @param [String,Symbol] receiver_method The name of the method that
121
+ # should be invoked upon the **receiver** object when the
122
+ # **attr_name** method is invoked. Defaults to a setter form of
123
+ # **attr_name**.
124
+ # @param [Class] builder_class The builder class that should be used
125
+ # to generate new objects when the **attr_name** method is invoked.
126
+ # Cannot be used in conjunction with a given **block**.
127
+ # @param [Proc,String,Symbol] receiver The object or method of the
128
+ # generated builder instance that should receive invocations of
129
+ # **receiver_method** when the **attr_name** method is called.
130
+ # Defaults to the {InstanceMethods#instance object instance} being
131
+ # built.
132
+ #
133
+ # If a String or Symbol value is provided for **receiver**, the value
134
+ # provided is resolved against the {InstanceMethods#instance object
135
+ # instance} being built at runtime to determine the appropriate
136
+ # receiver.
137
+ #
138
+ # For example if a value of :foo were provided for the **receiver**
139
+ # argument, at runtime, the **receiver** would be resolved to the
140
+ # object returned by invoking :foo on the {InstanceMethods#instance
141
+ # object instance} being built. Once resolved, the **receiver_method**
142
+ # would then be invoked on the **receiver** with any approprate
143
+ # arguments.
144
+ #
145
+ # If a Proc is provided for the **receiver** argument, the Proc will
146
+ # be evaluated at runtime in the context of the
147
+ # {InstanceMethods#instance object instance} being built and should
148
+ # return the intended **receiver** object.
149
+ # @param [Proc] block A block may be provided in place of a predefined
150
+ # **builder_class**. If such a block is provided, the given block is
151
+ # evaluated by {BuildingBlocks.build} to generate a new anonymous
152
+ # builder class. Cannot be used in conjunction with a predefined
153
+ # **builder_class**.
154
+ # @raise [ArgumentError] Raised if both a **builder_class** and a
155
+ # **block** are given or neither a **builder_class** nor **block** are
156
+ # given.
157
+ # @return [Symbol] The Symbol identifier form of **attr_name**
158
+ # identifying the method that will be available to instances of the
159
+ # generated builder class.
160
+ # @see BuildingBlocks.build
161
+ # @see #define_builder_method
162
+ # @see InstanceMethods#example_builder_attr
163
+ def builder(attr_name, receiver_method = "#{attr_name}=", builder_class = nil, receiver = nil)
164
+ if block_given? ^ builder_class.nil?
165
+ raise ArgumentError, 'Either a builder class or a builder definition is required'
166
+ elsif block_given?
167
+ builder_class = BuildingBlocks.build(&Proc.new)
168
+ end
169
+
170
+ if receiver.is_a?(Proc)
171
+ receiver_proc = receiver
172
+ elsif receiver.is_a?(Symbol) || receiver.is_a?(String)
173
+ receiver_proc = instance_eval("lambda { |i| @instance.#{receiver} }")
174
+ else
175
+ receiver_proc = lambda { |i| @instance }
176
+ end
177
+
178
+ define_builder_method(attr_name, receiver_method, builder_class, receiver_proc)
179
+ attr_name.to_sym
180
+ end
181
+
182
+ # Declares a delegate method that will be available to instances of the
183
+ # generated builder class that describes a behavior that should be
184
+ # delegated from the builder instance to the **receiver_method** of the
185
+ # derived **receiver**.
186
+ #
187
+ # @param [String,Symbol] attr_name An identifer that will be used to
188
+ # name the delegate method defined on the builder instance.
189
+ # @param [String,Symbol] receiver_method The method that should be
190
+ # invoked on the **receiver** when the delegate method is invoked.
191
+ # Defaults to the same value provided for **attr_name**.
192
+ # @param [String,Symbol] receiver The object or method of the
193
+ # generated builder instance that should receive invocations of
194
+ # **receiver_method** when the **attr_name** method is called.
195
+ # Defaults to the {InstanceMethods#instance object instance} being
196
+ # built.
197
+ #
198
+ # If a String or Symbol value is provided for **receiver**, the value
199
+ # provided is resolved against the {InstanceMethods#instance object
200
+ # instance} being built at runtime to determine the appropriate
201
+ # **receiver**.
202
+ #
203
+ # For example if a value of :foo were provided for the **receiver**
204
+ # argument, at runtime, the **receiver** would be resolved to the
205
+ # object returned by invoking :foo on the {InstanceMethods#instance
206
+ # object instance} being built. Once resolved, the **receiver_method**
207
+ # would then be invoked on the **receiver** with any approprate
208
+ # arguments.
209
+ # @return [Symbol] The Symbol identifier form of **attr_name**
210
+ # identifying the method that will be available to instances of the
211
+ # generated builder class.
212
+ def delegate(attr_name, receiver_method = attr_name, receiver = nil)
213
+ receiver = receiver.nil? || receiver.empty? ? :@instance : :"@instance.#{receiver}"
214
+ def_delegator(receiver, receiver_method, attr_name)
215
+ attr_name.to_sym
216
+ end
217
+
218
+ # When no block is given, returns the proc currently configured to be
219
+ # invoked when a new instance of {#resource_class resource class} is
220
+ # needed. If a custom proc has not been configured, returns the
221
+ # {DEFAULT_INITIALIZE_WITH default initialization proc}.
222
+ #
223
+ # When a block is given, the method acts as a setter and the provided
224
+ # block is preserved and later used to initialize new instances of
225
+ # {#resource_class resource class} as they are required.
226
+ # @return [Proc] The proc that will be used to initialize new instances
227
+ # of {#resouce_class resource class}.
228
+ def initialize_with
229
+ @initialize_with = Proc.new if block_given?
230
+ @initialize_with || DEFAULT_INITIALIZE_WITH
231
+ end
232
+
233
+ # Sets a custom proc to be used when initializing new instances of
234
+ # {#resource_class resource class}.
235
+ # @param [Proc] initializer The proc to be used to initialize new
236
+ # instances or {resource_class resource class}.
237
+ # @raise [ArgumentError] Raised if the provided **initializer** is
238
+ # missing or is not a proc.
239
+ # @return [Proc] The **initializer** argument provided is returned.
240
+ def initialize_with=(initializer)
241
+ unless initializer.is_a?(Proc)
242
+ raise ArgumentError, "Expected proc initializer, got #{initializer.class.name}"
243
+ end
244
+ @initialize_with = initializer
245
+ end
246
+
247
+ # The class that the generated builder class should generate instances
248
+ # of. When no value is passed for the **klass** argument, returns the
249
+ # currently configured resource class. If a value is provided for
250
+ # **klass**, the method acts as a setter and the provided **klass**
251
+ # argument is preserved and later used for the resource class of the
252
+ # generated builder class. For further information on how instances of
253
+ # the {#resource_class resource class} are built, see {#initialize_with}.
254
+ # @return [Object] The class that the generated builder class will
255
+ # generate instances of.
256
+ # @see #initialize_with
257
+ def resource_class(klass = nil)
258
+ @resource_class = klass unless klass.nil?
259
+ @resource_class
260
+ end
261
+
262
+ # Sets the class that the generated builder class will generate
263
+ # instances of. For further information on how instances of the
264
+ # {resource_class resource class} are built, see {#initialize_with}.
265
+ # @return [Object] The value given for the **klass** argument is
266
+ # returned.
267
+ # @see #initialize_with
268
+ def resource_class=(klass)
269
+ @resource_class = klass
270
+ end
271
+
272
+ private
273
+
274
+ # Handles the wiring required to invoke a builder when **attr_name** is
275
+ # invoked.
276
+ def define_builder_method(attr_name, receiver_method, builder_class, receiver_proc)
277
+ define_method(attr_name) do |existing_object = nil, &block|
278
+ begin
279
+ if block.nil? ^ !!existing_object
280
+ raise ArgumentError, 'Either a static instance or a builder proc is required'
281
+ end
282
+ receiver = instance_eval(&receiver_proc)
283
+ instance = block.nil? ? existing_object : builder_class.build(&block)
284
+ receiver.send(receiver_method, instance)
285
+ instance
286
+ rescue Exception
287
+ $@.delete_if{|s| %r"#{Regexp.quote(__FILE__)}"o =~ s}
288
+ ::Kernel::raise
289
+ end
290
+ end
291
+ end
292
+ end
293
+
294
+ # Methods available to instances of a generated builder class.
295
+ module InstanceMethods
296
+ # Initializes a new instance of the generated builder class. Requires
297
+ # the {ClassInstanceMethods#resource_class resource class} **instance**
298
+ # that the builder will populate to be provided.
299
+ # @param [Object] instance The object that should be populated by the
300
+ # builder instance.
301
+ def initialize(instance)
302
+ @instance = instance
303
+ end
304
+
305
+ # Returns the {InstanceMethods#instance object instance} being built by
306
+ # the builder instance.
307
+ # @return [Object] The {InstanceMethods#instance object instance} being
308
+ # built by the builder.
309
+ def instance
310
+ return @instance
311
+ end
312
+
313
+ # @!method example_builder_attr(existing_object = nil, &block)
314
+ # Reference for instance methods defined via {ClassInstanceMethods#builder}.
315
+ #
316
+ # This method is not actually defined, but serves as a reference for
317
+ # the instance method defined when an attribute is defined on the
318
+ # parent builder class using {ClassInstanceMethods#builder}.
319
+ #
320
+ # Invokes the `receiver_method` of `receiver` with the provided
321
+ # **existing_object** or a new object generated by invoking the
322
+ # *build* method of the derived `builder_class` with the given
323
+ # **block**.
324
+ # @param [Object] existing_object An existing object to use as the
325
+ # argument to `receiver_method`. Cannot be used in conjunction
326
+ # with a block.
327
+ # @param [Proc] block A block to be given to the *build* method of
328
+ # the derived `builder_class` to generate a new object. Cannot be
329
+ # used in conjunction with a provided **existing_object**.
330
+ # @raise [ArgumentError] Raised if both an **existing_object** and
331
+ # **block** are given or neither an **existing_object** nor
332
+ # **block** are provided.
333
+ # @return [Object] The provided **existing_object** or the object
334
+ # generated by invoking the *build* method of the `builder_class`
335
+ # with the given **block**.
336
+ # @see ClassInstanceMethods#builder
337
+ end
338
+
339
+ end
340
+ end
341
+ end
@@ -0,0 +1,4 @@
1
+ module BuildingBlocks
2
+ # The version of BuildingBlocks in use.
3
+ VERSION = '0.0.1'
4
+ end
@@ -0,0 +1,10 @@
1
+ if ENV['CI']
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+ end
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest/unit'
8
+ require 'mocha/setup'
9
+ require 'shoulda/context'
10
+ require 'building_blocks'
@@ -0,0 +1,406 @@
1
+ require 'test_helper'
2
+
3
+ module BuildingBlocks
4
+ module Builders
5
+ class BuilderBuilderTest < MiniTest::Test
6
+
7
+ context 'BuilderBuilder class methods' do
8
+
9
+ should 'generate a new Builder class without block given' do
10
+ builder = BuilderBuilder.build
11
+ assert_kind_of Class, builder
12
+ assert builder.ancestors.include?(BuildingBlocks::Builders::BuilderBuilder::InstanceMethods)
13
+ end
14
+
15
+
16
+ should 'generate a new Builder class with block given' do
17
+ new_block_arg = new_self = nil
18
+ # Validates block form
19
+ builder = BuilderBuilder.build do |subclass|
20
+ # Leave marker of instance evaluation
21
+ define_singleton_method(:builder_evaluated) { true }
22
+ # Test usage of block argument
23
+ subclass.resource_class = Hash
24
+ # Set up variables for evaluation back in the test
25
+ new_self = self
26
+ new_block_arg = subclass
27
+ end
28
+
29
+ # Validate DSL context variables
30
+ assert_equal builder, new_block_arg
31
+ assert_equal builder, new_self
32
+
33
+ # Validate assignments and markers
34
+ assert_equal Hash, builder.resource_class
35
+ assert_equal true, builder.builder_evaluated
36
+ end
37
+
38
+ end
39
+
40
+
41
+ context 'BuilderBuilder generated Builder class methods' do
42
+
43
+ setup do
44
+ @struct = struct = Struct.new(:key, :value)
45
+ @dict_builder = BuildingBlocks.build do
46
+ resource_class struct
47
+ attribute(:key)
48
+ attribute(:value)
49
+ end
50
+ @builder = BuildingBlocks.build
51
+ end
52
+
53
+
54
+ context '::attribute' do
55
+
56
+ should 'raise ArgumentError unless attribute name provided' do
57
+ assert_raises(ArgumentError) { BuildingBlocks.build { attribute } }
58
+ end
59
+
60
+
61
+ should 'delegate calls to attr_name to receiver via receiver_method' do
62
+ @builder.expects(:def_delegator).with(:'@instance.c', :b, :a,)
63
+ @builder.attribute(:a, :b, :c)
64
+ end
65
+
66
+
67
+ should 'delegate to attr_name= on receiver by default' do
68
+ @builder.expects(:def_delegator).with(:@instance, :a=, :a,)
69
+ @builder.attribute(:a)
70
+ end
71
+
72
+
73
+ should 'delegate directly to the @instance by default' do
74
+ @builder.expects(:def_delegator).with(:@instance, :a=, :a)
75
+ @builder.attribute(:a)
76
+ end
77
+
78
+
79
+ should 'return the Symbol form of the provided attr_name' do
80
+ result = @builder.attribute(:a)
81
+ assert_equal :a, result
82
+ end
83
+
84
+ end
85
+
86
+
87
+ context '::builder' do
88
+
89
+ should 'raise an error unless a Builder class xor proc is provided' do
90
+ assert_raises(ArgumentError) do
91
+ BuildingBlocks.build { builder(:foo) }
92
+ end
93
+
94
+ dict_builder = @dict_builder
95
+ assert_raises(ArgumentError) do
96
+ BuildingBlocks.build { builder(:foo, :foo=, dict_builder) { |i| } }
97
+ end
98
+ end
99
+
100
+
101
+ should 'raise an error unless an attr_name is provided' do
102
+ assert_raises(ArgumentError) { BuildingBlocks.build { builder } }
103
+ end
104
+
105
+
106
+ should 'return the Symbol form of the provided attr_name' do
107
+ dict_builder = @dict_builder
108
+ result = @builder.builder(:foo, :value=, dict_builder)
109
+ assert_equal :foo, result
110
+ end
111
+
112
+
113
+ should 'take a custom receiver method name' do
114
+ dict_builder, struct = @dict_builder, @struct
115
+ builder = BuildingBlocks.build do
116
+ resource_class struct
117
+ builder(:foo, :value=, dict_builder)
118
+ end
119
+ instance = builder.build { foo { key(:a); value(:b) } }
120
+ assert_equal :a, instance.value.key
121
+ assert_equal :b, instance.value.value
122
+ end
123
+
124
+
125
+ should 'take a custom receiver proc' do
126
+ dict_builder, struct = @dict_builder, @struct
127
+ builder = BuildingBlocks.build do
128
+ resource_class struct
129
+ builder(:foo, :value=, dict_builder, lambda { |i| String })
130
+ end
131
+ String.expects(:value=)
132
+ builder.build { foo { key(:a); value(:b) } }
133
+ end
134
+
135
+
136
+ should 'should accept a proc that is a Builder definition' do
137
+ struct = @struct
138
+ builder = BuildingBlocks.build do
139
+ resource_class struct
140
+ builder(:foo, :value=) do |i|
141
+ resource_class struct
142
+ attribute :bar, :key=
143
+ end
144
+ end
145
+ instance = builder.build { foo { bar :a } }
146
+ assert_equal :a, instance.value.key
147
+ end
148
+
149
+
150
+ should 'accept a custom builder class' do
151
+ dict_builder, struct = @dict_builder, @struct
152
+ db = dict_builder.build
153
+ dict_builder.expects(:build).returns(db)
154
+ builder = BuildingBlocks.build do
155
+ resource_class struct
156
+ builder(:foo, :value=, dict_builder)
157
+ end
158
+ instance = builder.build { foo { |i| } }
159
+ assert_equal db, instance.value
160
+ end
161
+
162
+
163
+ should 'accept a custom receiver identifier' do
164
+ dict_builder, struct = @dict_builder, @struct
165
+ builder = BuildingBlocks.build do
166
+ resource_class struct
167
+ builder(:value, :value=, dict_builder)
168
+ builder(:foo, :value=, dict_builder, :value)
169
+ end
170
+ instance = builder.build do
171
+ value { key(:a) }
172
+ foo { |i| value(:b) }
173
+ end
174
+ assert_equal :b, instance.value.value.value
175
+ end
176
+
177
+ end
178
+
179
+
180
+ context '::delegate' do
181
+
182
+ should 'raise ArgumentError unless method_name provided' do
183
+ assert_raises(ArgumentError) { @builder.delegate }
184
+ end
185
+
186
+
187
+ should 'create a delegator to @instance.receiver.receiver_method aliased to method_name' do
188
+ @builder.expects(:def_delegator).with(:'@instance.receiver', :receiver_method, :method_name)
189
+ @builder.delegate(:method_name, :receiver_method, :receiver)
190
+ end
191
+
192
+
193
+ should 'create a delegator to @instance.receiver_method aliased to method_name by default' do
194
+ @builder.expects(:def_delegator).with(:@instance, :receiver_method, :method_name)
195
+ @builder.delegate(:method_name, :receiver_method)
196
+ end
197
+
198
+
199
+ should 'create a delegator to @instance.method_name aliased to method_name by default' do
200
+ @builder.expects(:def_delegator).with(:@instance, :method_name, :method_name)
201
+ @builder.delegate(:method_name)
202
+ end
203
+
204
+
205
+ should 'return the symbol identifier form of attr_name' do
206
+ assert_equal :method_name, @builder.delegate('method_name')
207
+ end
208
+
209
+ end
210
+
211
+
212
+ context '::new' do
213
+
214
+ should 'accept a block and evaluate the block on the builder instance' do
215
+ struct = @dict_builder.build do
216
+ key :a
217
+ value 'a'
218
+ end
219
+ assert_equal :a, struct.key
220
+ assert_equal 'a', struct.value
221
+ end
222
+
223
+
224
+ should 'return the generated instance when no block given' do
225
+ the_struct = @struct.new
226
+ the_struct.key = :a
227
+ the_struct.value = 'a'
228
+ @struct.expects(:new).returns(the_struct)
229
+
230
+ struct = @dict_builder.build
231
+ assert_equal :a, struct.key
232
+ assert_equal 'a', struct.value
233
+ end
234
+
235
+
236
+ should 'utilize a custom initialize_with proc if available' do
237
+ @dict_builder.initialize_with do |builder|
238
+ instance = resource_class.new
239
+ instance.key = :b
240
+ instance.value = 'b'
241
+ instance
242
+ end
243
+
244
+ struct = @dict_builder.build
245
+ assert_equal :b, struct.key
246
+ assert_equal 'b', struct.value
247
+ end
248
+
249
+ end
250
+
251
+
252
+ context '::initialize_with' do
253
+
254
+ setup do
255
+ @initializer = lambda { |i| Hash.new }
256
+ @dict_builder.initialize_with(&@initializer)
257
+ end
258
+
259
+
260
+ should 'set @initialize_with if given a block' do
261
+ assert_equal @dict_builder.initialize_with, @initializer
262
+ assert_equal @dict_builder.instance_variable_get(:@initialize_with), @initializer
263
+ end
264
+
265
+
266
+ should 'return @initialize_with if no block given' do
267
+ assert_equal @dict_builder.instance_variable_get(:@initialize_with), @dict_builder.initialize_with
268
+ end
269
+
270
+ end
271
+
272
+
273
+ context '::initialize_with=' do
274
+
275
+ setup do
276
+ @initializer = lambda { |i| Hash.new }
277
+ end
278
+
279
+
280
+ should 'raise an error if a non-proc is provided' do
281
+ assert_raises(ArgumentError) do
282
+ @dict_builder.initialize_with = :foo
283
+ end
284
+ end
285
+
286
+
287
+ should 'set @initialize_with if given a proc' do
288
+ @dict_builder.initialize_with = @initializer
289
+ assert_equal @dict_builder.initialize_with, @initializer
290
+ assert_equal @dict_builder.instance_variable_get(:@initialize_with), @initializer
291
+ end
292
+
293
+ end
294
+
295
+
296
+ context '::resource_class' do
297
+
298
+ should 'return the current resource_class when no arguments are given' do
299
+ assert_equal nil, @builder.resource_class
300
+ @builder.resource_class = @struct
301
+ assert_equal @struct, @builder.resource_class
302
+ end
303
+
304
+
305
+ should 'set the current resource_class when an argument is given' do
306
+ @builder.resource_class(@struct)
307
+ assert_equal @struct, @builder.resource_class
308
+ end
309
+
310
+
311
+ should 'set and return the argument given when given an argument' do
312
+ assert_equal @struct, @builder.resource_class(@struct)
313
+ end
314
+
315
+ end
316
+
317
+
318
+ context '::resource_class=' do
319
+
320
+ should 'set the current resource_class' do
321
+ @builder.resource_class = @struct
322
+ assert_equal @struct, @builder.resource_class
323
+ end
324
+
325
+
326
+ should 'return the argument given' do
327
+ assert_equal @struct, @builder.resource_class = @struct
328
+ end
329
+
330
+ end
331
+
332
+ end
333
+
334
+
335
+ context 'BuilderBuilder generated Builder class instance methods' do
336
+
337
+ setup do
338
+ @struct = struct = Struct.new(:key, :value)
339
+ @dict_builder = BuildingBlocks.build do
340
+ resource_class struct
341
+ attribute(:key)
342
+ attribute(:value)
343
+ end
344
+ end
345
+
346
+
347
+ context '::builder generated instance method' do
348
+
349
+ setup do
350
+ dict_builder, struct = @dict_builder, @struct
351
+ @builder_instance = BuildingBlocks.build do
352
+ resource_class struct
353
+ builder(:foo, :value=, dict_builder)
354
+ end
355
+ end
356
+
357
+
358
+ should 'raise ArgumentError if given static instance and block or neither' do
359
+ assert_raises(ArgumentError) { @builder_instance.build { foo } }
360
+ assert_raises(ArgumentError) do
361
+ @builder_instance.build { foo(true) {|i| } }
362
+ end
363
+ end
364
+
365
+
366
+ should 'pass a static instance to the receiver method of the receiver' do
367
+ instance = @builder_instance.build { foo(true) }
368
+ assert_equal true, instance.value
369
+ end
370
+
371
+
372
+ should 'evaluate builder definition and send instance to the receiver method of receiver' do
373
+ instance = @builder_instance.build { foo { value(true) } }
374
+ assert_equal true, instance.value.value
375
+ end
376
+
377
+ end
378
+
379
+
380
+ context '#initialize' do
381
+
382
+ should 'require an instance' do
383
+ assert_raises(ArgumentError) { @dict_builder.new }
384
+ struct = @struct.new(:k, :v)
385
+ builder = @dict_builder.new(struct)
386
+ assert_equal struct, builder.instance
387
+ end
388
+
389
+ end
390
+
391
+
392
+ context '#instance' do
393
+
394
+ should 'return the object instance being built' do
395
+ struct = @struct.new(:k, :v)
396
+ builder = @dict_builder.new(struct)
397
+ assert_equal struct, builder.instance
398
+ end
399
+
400
+ end
401
+
402
+ end
403
+
404
+ end
405
+ end
406
+ end
@@ -0,0 +1,136 @@
1
+ require 'test_helper'
2
+
3
+ class BuildingBlocksTest < MiniTest::Test
4
+
5
+ DEFAULT_BUILDER = BuildingBlocks::DEFAULT_DEFINITION_BUILDER
6
+
7
+ context 'BuildingBlocks' do
8
+
9
+ should 'be defined' do
10
+ assert BuildingBlocks
11
+ end
12
+
13
+
14
+ context 'Factory methods' do
15
+
16
+ context '::build' do
17
+
18
+ setup do
19
+ @builder = BuildingBlocks.build
20
+ end
21
+
22
+
23
+ should 'return a default Builder instance when no block given' do
24
+ assert_kind_of Class, @builder
25
+ assert @builder.ancestors.include?(BuildingBlocks::Builders::BuilderBuilder::InstanceMethods)
26
+ end
27
+
28
+
29
+ should 'return an evaluated Builder instance when block is given' do
30
+ struct = Struct.new(:key, :value)
31
+
32
+ dict_builder = BuildingBlocks.build do |b|
33
+ resource_class struct
34
+ attribute :key
35
+ attribute :value
36
+ end
37
+
38
+ struct_dict_builder = BuildingBlocks.build do |i|
39
+ resource_class struct
40
+ attribute(:key)
41
+ builder(:value, :value=, dict_builder)
42
+ delegate(:inner_value, :value=, 'value')
43
+ end
44
+
45
+ dict = dict_builder.build do |b|
46
+ key(:a)
47
+ value(:b)
48
+ end
49
+ assert_equal :a, dict.key
50
+ assert_equal :b, dict.value
51
+
52
+ struct_dict = struct_dict_builder.build do |b|
53
+ key(:c)
54
+ value do
55
+ key(:d)
56
+ end
57
+ inner_value(:e)
58
+ end
59
+ assert_equal :c, struct_dict.key
60
+ assert_equal :d, struct_dict.value.key
61
+ assert_equal :e, struct_dict.value.value
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+
69
+ context 'configuration' do
70
+
71
+ setup do
72
+ @original_config = BuildingBlocks.default_builder
73
+ @simple_builder = Class.new do
74
+ attr_accessor :args, :block
75
+ def self.build(*args)
76
+ instance = new
77
+ instance.block = Proc.new if block_given?
78
+ instance.args = args
79
+ instance
80
+ end
81
+ end
82
+ end
83
+
84
+
85
+ teardown do
86
+ BuildingBlocks.default_builder = @original_config
87
+ end
88
+
89
+
90
+ context '::default_builder' do
91
+
92
+ should 'return @default_defintion_builder or DEFAULT_DEFINITION_BUILDER' do
93
+ BuildingBlocks.default_builder = nil
94
+ assert_equal BuildingBlocks.default_builder, DEFAULT_BUILDER
95
+ BuildingBlocks.default_builder = @simple_builder
96
+ assert_equal BuildingBlocks.default_builder, @simple_builder
97
+ end
98
+
99
+ end
100
+
101
+
102
+ context '::default_builder=' do
103
+
104
+ [nil, false].each do |value|
105
+ should "accept #{value.inspect} to reset the default_builder" do
106
+ BuildingBlocks.default_builder = @simple_builder
107
+ assert_equal BuildingBlocks.default_builder, @simple_builder
108
+ BuildingBlocks.default_builder = value
109
+ assert_equal BuildingBlocks.default_builder, DEFAULT_BUILDER
110
+ end
111
+ end
112
+
113
+
114
+ should 'raise an error if the proivded object does not respond to #build' do
115
+ BuildingBlocks.default_builder = nil
116
+ assert_equal BuildingBlocks.default_builder, DEFAULT_BUILDER
117
+ assert_raises(ArgumentError) do
118
+ BuildingBlocks.default_builder = Class.new
119
+ end
120
+ end
121
+
122
+
123
+ should 'set the default_builder' do
124
+ BuildingBlocks.default_builder = nil
125
+ assert_equal BuildingBlocks.default_builder, DEFAULT_BUILDER
126
+ BuildingBlocks.default_builder = @simple_builder
127
+ assert_equal BuildingBlocks.default_builder, @simple_builder
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+
136
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: building_blocks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Danny Guinther
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
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
+ description: Simple DSL for defining block-based Object builders
42
+ email:
43
+ - dannyguinther@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".travis.yml"
50
+ - ".yardopts"
51
+ - Gemfile
52
+ - Guardfile
53
+ - LICENSE
54
+ - README.md
55
+ - Rakefile
56
+ - building_blocks.gemspec
57
+ - lib/building_blocks.rb
58
+ - lib/building_blocks/builders/builder_builder.rb
59
+ - lib/building_blocks/version.rb
60
+ - test/test_helper.rb
61
+ - test/unit/builders/builder_builder_test.rb
62
+ - test/unit/building_blocks_test.rb
63
+ homepage: https://github.com/interval-braining/building_blocks
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.2.2
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Block-based Object Builders
87
+ test_files:
88
+ - test/test_helper.rb
89
+ - test/unit/builders/builder_builder_test.rb
90
+ - test/unit/building_blocks_test.rb
91
+ has_rdoc: