carpenter 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.
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +143 -0
- data/Rakefile +1 -0
- data/carpenter.gemspec +24 -0
- data/lib/carpenter.rb +29 -0
- data/lib/carpenter/build_dsl.rb +7 -0
- data/lib/carpenter/builder_loader.rb +25 -0
- data/lib/carpenter/define_dsl.rb +7 -0
- data/lib/carpenter/version.rb +3 -0
- data/spec/carpenter/build_dsl_spec.rb +27 -0
- data/spec/carpenter/builder_loader_spec.rb +45 -0
- data/spec/carpenter/define_dsl_spec.rb +16 -0
- data/spec/carpenter_spec.rb +59 -0
- data/spec/fixtures/builders/a.rb +1 -0
- data/spec/fixtures/builders/b.rb +1 -0
- data/spec/spec_helper.rb +11 -0
- metadata +105 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Alexander Kern
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
Carpenter
|
2
|
+
=========
|
3
|
+
|
4
|
+
Description
|
5
|
+
-----------
|
6
|
+
|
7
|
+
Carpenter provides syntax sugar for using the [Test Data Builder][tdb-pattern]
|
8
|
+
pattern in Ruby testing frameworks. It complements [FactoryGirl][factory-girl]
|
9
|
+
and mock objects.
|
10
|
+
|
11
|
+
[tdb-pattern]: http://c2.com/cgi/wiki?TestDataBuilder
|
12
|
+
[factory-girl]: https://github.com/thoughtbot/factory_girl
|
13
|
+
|
14
|
+
Why?
|
15
|
+
----
|
16
|
+
|
17
|
+
Sometimes, instantiating a test object is really ugly. For example, [Value
|
18
|
+
Objects][value-objects] will very often have long declarations.
|
19
|
+
|
20
|
+
Webbed::Method.new("GET", :safe => true, :idempotent => true, :allows_request_entity => false, :allows_response_entity => true)
|
21
|
+
|
22
|
+
Wouldn't it be nice if we could put this ugliness in a separate file? Carpenter
|
23
|
+
allows you to define "builders" which can be reused in different test files.
|
24
|
+
|
25
|
+
# in spec/builders/method.rb
|
26
|
+
Carpenter.define do
|
27
|
+
builder :get_method do
|
28
|
+
Webbed::Method.new("GET", :safe => true, :idempotent => true, :allows_request_entity => false, :allows_response_entity => true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# in spec/webbed/method_spec.rb
|
33
|
+
Carpenter(:get_method) # => a new Webbed::Method
|
34
|
+
|
35
|
+
This pattern looks similar to FactoryGirl; however, Carpenter is *not* a
|
36
|
+
substitute for FactoryGirl and its alternatives. FactoryGirl was designed to
|
37
|
+
generate ActiveRecord models. Carpenter was designed to generate any kind of
|
38
|
+
Ruby object. Prefer FactoryGirl over Carpenter whenever possible.
|
39
|
+
|
40
|
+
Carpenter is also *not* a substitute for mock objects. Build objects using Carpenter
|
41
|
+
if they are the object currently under test. Use mocks or stubs if you are not
|
42
|
+
testing the object, but instead testing one of its associates.
|
43
|
+
|
44
|
+
[value-objects]: http://c2.com/cgi/wiki?ValueObject
|
45
|
+
|
46
|
+
Installation
|
47
|
+
------------
|
48
|
+
|
49
|
+
First, install the gem.
|
50
|
+
|
51
|
+
gem install carpenter
|
52
|
+
|
53
|
+
For RSpec users, add the following to your `spec_helper.rb`:
|
54
|
+
|
55
|
+
require "carpenter"
|
56
|
+
|
57
|
+
Carpenter::BuilderLoader.load_all
|
58
|
+
RSpec.configure do |config|
|
59
|
+
config.include Carpenter::BuildDSL
|
60
|
+
end
|
61
|
+
|
62
|
+
For `Test::Unit` users, add the following to your `test_helper.rb`:
|
63
|
+
|
64
|
+
require "carpenter"
|
65
|
+
|
66
|
+
Carpenter::BuilderLoader.load_all
|
67
|
+
class Test::Unit::TestCase
|
68
|
+
include Carpenter::BuildDSL
|
69
|
+
end
|
70
|
+
|
71
|
+
Other testing frameworks should work with Carpenter if they support including a
|
72
|
+
Ruby module. All you have to do is call `Carpenter::BuilderLoader.load_all` and include
|
73
|
+
`Carpenter::BuildDSL` into the framework. Please submit a GitHub if there are
|
74
|
+
any issues with some frameworks.
|
75
|
+
|
76
|
+
Usage
|
77
|
+
-----
|
78
|
+
|
79
|
+
By default, Carpenter loads all the files from `test/builders` and
|
80
|
+
`spec/builders`. I'd suggest making a builder file for each class that you
|
81
|
+
build. Each file should be wrapped in a `Carpenter.define` block like so:
|
82
|
+
|
83
|
+
# in spec/builders/my_object.rb
|
84
|
+
Carpenter.define do
|
85
|
+
# Your builders go here.
|
86
|
+
end
|
87
|
+
|
88
|
+
You can define builders using the `#builder` method. It takes a symbol as the
|
89
|
+
name of the builder and a block as the actual builder. Here's a really simple
|
90
|
+
builder that will make a new instance of `MyObject` with some arguments:
|
91
|
+
|
92
|
+
# in spec/builders/my_object.rb
|
93
|
+
Carpenter.define do
|
94
|
+
builder :my_object do
|
95
|
+
MyObject.new(:foo, :bar)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
Builders also can take an optional hash of options to let you configure the
|
100
|
+
test data a bit.
|
101
|
+
|
102
|
+
# in spec/builders/my_object.rb
|
103
|
+
Carpenter.define do
|
104
|
+
builder :my_object do |options|
|
105
|
+
MyObject.new(options[:foo], options[:bar])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Builders can be named whatever you want and return whatever you want. They're
|
110
|
+
essentially methods. So, this is just as valid as the last example, [albeit a
|
111
|
+
bit confusing][confusing]:
|
112
|
+
|
113
|
+
# in spec/builders/abraham_lincoln.rb
|
114
|
+
Carpenter.define do
|
115
|
+
builder :abraham_lincoln_quote do
|
116
|
+
"The trouble with quotes on the Internet is that you can never know if they are genuine."
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
To use your builders in your tests, just use the `#Carpenter` method with the
|
121
|
+
name of the builder and (optionally) a hash of options.
|
122
|
+
|
123
|
+
# in spec/my_object_spec.rb
|
124
|
+
describe MyObject do
|
125
|
+
it "can be created" do
|
126
|
+
Carpenter(:my_object).should_not be_nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
You can add more builder load directories by adding them to the builder
|
131
|
+
loader's builder paths before loading the builders.
|
132
|
+
|
133
|
+
Carpenter::BuilderLoader.builder_paths << "spec/custom_builder_dir"
|
134
|
+
Carpenter::BuilderLoader.load_all
|
135
|
+
|
136
|
+
[confusing]: http://www.comedyshack.co.za/wp-content/uploads/2011/02/trouble-with-quotes-on-internet.png
|
137
|
+
|
138
|
+
License
|
139
|
+
-------
|
140
|
+
|
141
|
+
Released under the MIT License. See the [LICENSE][license] file for details.
|
142
|
+
|
143
|
+
[license]: https://github.com/CapnKernul/carpenter/blob/develop/LICENSE
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/carpenter.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "carpenter/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "carpenter"
|
7
|
+
s.version = Carpenter::VERSION
|
8
|
+
s.authors = ["Alexander Kern"]
|
9
|
+
s.email = ["alex@kernul.com"]
|
10
|
+
s.homepage = "https://github.com/CapnKernul/carpenter"
|
11
|
+
s.summary = %q{The Test Data Builder pattern for Ruby.}
|
12
|
+
s.description = %q{Tiny gem for specifying test data for arbitrary objects in Ruby.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "carpenter"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rspec", "~> 2.7"
|
22
|
+
s.add_development_dependency "rake", "~> 0.9"
|
23
|
+
s.add_development_dependency "fuubar", "0.0.6"
|
24
|
+
end
|
data/lib/carpenter.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "carpenter/version"
|
2
|
+
|
3
|
+
module Carpenter
|
4
|
+
def self.builders
|
5
|
+
@builders ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.define_builder(name, &builder)
|
9
|
+
builders[name] = builder
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.clear
|
13
|
+
@builders = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.build(name, options = {})
|
17
|
+
builder = builders[name]
|
18
|
+
builder.call(options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.define(&block)
|
22
|
+
dsl = Carpenter::DefineDSL.new
|
23
|
+
dsl.instance_eval(&block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require "carpenter/build_dsl"
|
28
|
+
require "carpenter/define_dsl"
|
29
|
+
require "carpenter/builder_loader"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Carpenter
|
2
|
+
module BuilderLoader
|
3
|
+
class << self
|
4
|
+
attr_accessor :builder_paths
|
5
|
+
end
|
6
|
+
|
7
|
+
self.builder_paths = %w{test/builders spec/builders}
|
8
|
+
|
9
|
+
def self.builder_absolute_paths
|
10
|
+
builder_paths.map { |p| File.expand_path(p) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.load_all
|
14
|
+
builder_absolute_paths.each do |p|
|
15
|
+
load_path(p) if File.directory?(p)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.load_path(path)
|
20
|
+
Dir[File.join(path, "**", "*.rb")].each do |f|
|
21
|
+
load f
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Carpenter::BuildDSL do
|
4
|
+
let(:builder) { lambda {} }
|
5
|
+
let(:dsl) do
|
6
|
+
klass = Class.new
|
7
|
+
klass.send(:include, Carpenter::BuildDSL)
|
8
|
+
klass.new
|
9
|
+
end
|
10
|
+
|
11
|
+
before do
|
12
|
+
Carpenter.define_builder(:test, &builder)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#Carpenter" do
|
16
|
+
it "calls the builder" do
|
17
|
+
builder.should_receive(:call)
|
18
|
+
dsl.Carpenter(:test)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns the built object" do
|
22
|
+
builder.stub(:call).and_return("I'm practically asleep.")
|
23
|
+
result = dsl.Carpenter(:test)
|
24
|
+
result.should == "I'm practically asleep."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Carpenter::BuilderLoader do
|
4
|
+
describe ".builder_paths" do
|
5
|
+
it "has 3 paths by default" do
|
6
|
+
Carpenter::BuilderLoader.should have(2).builder_paths
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".builder_absolute_paths" do
|
11
|
+
it "has the absolute paths of the builder paths" do
|
12
|
+
Carpenter::BuilderLoader.should have(2).builder_absolute_paths
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".load_all" do
|
17
|
+
before do
|
18
|
+
Carpenter::BuilderLoader.builder_paths << "spec/fixtures/builders"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "loads each builder in each directory" do
|
22
|
+
Carpenter::BuilderLoader.load_all
|
23
|
+
A_INCLUDED.should be_true
|
24
|
+
B_INCLUDED.should be_true
|
25
|
+
end
|
26
|
+
|
27
|
+
after do
|
28
|
+
Object.send(:remove_const, :A_INCLUDED)
|
29
|
+
Object.send(:remove_const, :B_INCLUDED)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe ".load_path" do
|
34
|
+
it "loads each builder in the directory" do
|
35
|
+
Carpenter::BuilderLoader.load_path("spec/fixtures/builders")
|
36
|
+
A_INCLUDED.should be_true
|
37
|
+
B_INCLUDED.should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
Object.send(:remove_const, :A_INCLUDED)
|
42
|
+
Object.send(:remove_const, :B_INCLUDED)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Carpenter::DefineDSL do
|
4
|
+
let(:dsl) { Carpenter::DefineDSL.new }
|
5
|
+
|
6
|
+
describe "#builder" do
|
7
|
+
it "creates a builder" do
|
8
|
+
dsl.builder(:test) do
|
9
|
+
:foo
|
10
|
+
end
|
11
|
+
|
12
|
+
result = Carpenter.build(:test)
|
13
|
+
result.should == :foo
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Carpenter do
|
4
|
+
let(:define_block) { lambda {} }
|
5
|
+
let(:builder) { lambda {} }
|
6
|
+
|
7
|
+
before do
|
8
|
+
Carpenter.define_builder(:test, &builder)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#define" do
|
12
|
+
it "exeutes the block in a new DefineDSL object" do
|
13
|
+
Carpenter.define do
|
14
|
+
builder :foo do
|
15
|
+
:bar
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
result = Carpenter.build(:foo)
|
20
|
+
result.should == :bar
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#define_builder" do
|
25
|
+
it "defines a new builder" do
|
26
|
+
Carpenter.builders[:test].should == builder
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#clear" do
|
31
|
+
it "removes all builders" do
|
32
|
+
Carpenter.clear
|
33
|
+
Carpenter.should have(0).builders
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#build" do
|
38
|
+
context "when provided options" do
|
39
|
+
it "calls the builder with the options" do
|
40
|
+
options = double("options")
|
41
|
+
builder.should_receive(:call).with(options)
|
42
|
+
Carpenter.build(:test, options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when not provided options" do
|
47
|
+
it "calls the builder with an empty options hash" do
|
48
|
+
builder.should_receive(:call).with({})
|
49
|
+
Carpenter.build(:test)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns the result of the builder" do
|
54
|
+
builder.stub(:call).and_return("I'm tired.")
|
55
|
+
result = Carpenter.build(:test)
|
56
|
+
result.should == "I'm tired."
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
A_INCLUDED = true
|
@@ -0,0 +1 @@
|
|
1
|
+
B_INCLUDED = true
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carpenter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alexander Kern
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-23 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70355091736740 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.7'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70355091736740
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &70355091726220 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0.9'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70355091726220
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: fuubar
|
38
|
+
requirement: &70355091725060 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - =
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.0.6
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70355091725060
|
47
|
+
description: Tiny gem for specifying test data for arbitrary objects in Ruby.
|
48
|
+
email:
|
49
|
+
- alex@kernul.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- .gitignore
|
55
|
+
- .rspec
|
56
|
+
- Gemfile
|
57
|
+
- LICENSE
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- carpenter.gemspec
|
61
|
+
- lib/carpenter.rb
|
62
|
+
- lib/carpenter/build_dsl.rb
|
63
|
+
- lib/carpenter/builder_loader.rb
|
64
|
+
- lib/carpenter/define_dsl.rb
|
65
|
+
- lib/carpenter/version.rb
|
66
|
+
- spec/carpenter/build_dsl_spec.rb
|
67
|
+
- spec/carpenter/builder_loader_spec.rb
|
68
|
+
- spec/carpenter/define_dsl_spec.rb
|
69
|
+
- spec/carpenter_spec.rb
|
70
|
+
- spec/fixtures/builders/a.rb
|
71
|
+
- spec/fixtures/builders/b.rb
|
72
|
+
- spec/spec_helper.rb
|
73
|
+
homepage: https://github.com/CapnKernul/carpenter
|
74
|
+
licenses: []
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project: carpenter
|
93
|
+
rubygems_version: 1.8.10
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: The Test Data Builder pattern for Ruby.
|
97
|
+
test_files:
|
98
|
+
- spec/carpenter/build_dsl_spec.rb
|
99
|
+
- spec/carpenter/builder_loader_spec.rb
|
100
|
+
- spec/carpenter/define_dsl_spec.rb
|
101
|
+
- spec/carpenter_spec.rb
|
102
|
+
- spec/fixtures/builders/a.rb
|
103
|
+
- spec/fixtures/builders/b.rb
|
104
|
+
- spec/spec_helper.rb
|
105
|
+
has_rdoc:
|