lumberjack-dsl 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6c16f341965b521bc70b58d4c946e1cd88475785
4
+ data.tar.gz: abe006e0b14bb8445d16530e2fd6d9ec7cb3351e
5
+ SHA512:
6
+ metadata.gz: f56c40263891f6866ce5ca91ea9a89cca75966b0679a8cd170da0fdf0de7cacdce9afd1a48dc808027c24ad78f99e2002826da6da593d83e9978cc924640b092
7
+ data.tar.gz: 4602359534dfaa35bef282194927415e1b3965a22e27945145ce2a0a69b70051d92146e7a49e42fcd68e05eac153acf36fb2d322ced83f94bd5e0e8818bd4984
@@ -1,57 +1,69 @@
1
+ # Lumberjack
2
+
1
3
  Lumberjack is best summed up as a generic DSL for constructing object trees.
2
4
 
3
5
  It works great for configuration files, for generating a tree of configuration
4
6
  objects for later reflection or what-not. But in reality you could use it for
5
7
  whatever you're willing to dream up.
6
8
 
9
+ # Installation
10
+
11
+ ```
12
+ gem install lumberjack-dsl
13
+ ```
14
+
15
+ # Usage
16
+
7
17
  I apologise for the lack of documentation :) Below is a code example to get you
8
18
  started, any questions, shoot me a message!
9
19
 
10
20
  Now, that code example:
11
21
 
12
- require 'lumberjack'
13
-
14
- class Person
15
-
16
- attr_accessor :age, :gripes, :chums
17
-
18
- def initialize(name)
19
- @name = name
20
- @gripes = []
21
- @chums = []
22
- end
23
- end
24
-
25
- class Gripe
26
- def initialize(desc)
27
- @desc = desc
28
- end
29
- end
30
-
31
- tree = Lumberjack.construct do
32
-
33
- # we're in list / instanciate object scope
34
-
35
- @john = person 'John (is a doondy head)' do
36
- # we instanticated an object, so now we're in attr assignment scope
37
- age 12 # this is equiv to @john.age = 12
38
- gripes do # open up a colection on john...
39
- # now we're back in list / instanticate object scope
40
- gripe 'untested code' # creating a gripe
41
- gripe 'no beer' # and another
42
- end # out of gripes, back to john attr assignment
43
- end # out of john
44
-
45
- # we're back to creating people:
46
-
47
- person 'Ryan' do
48
- age 25
49
- end
50
-
51
- person 'Tim' do
52
- age 'Infinite'
53
- chums @john # instance vars are shared across Lumberjack.construct
54
- end
55
- end
56
-
57
- puts tree.inspect
22
+ ```ruby
23
+ require 'lumberjack'
24
+
25
+ class Person
26
+
27
+ attr_accessor :age, :gripes, :chums
28
+
29
+ def initialize(name)
30
+ @name = name
31
+ @gripes = []
32
+ @chums = []
33
+ end
34
+ end
35
+
36
+ class Gripe
37
+ def initialize(desc)
38
+ @desc = desc
39
+ end
40
+ end
41
+
42
+ tree = Lumberjack.construct do
43
+
44
+ # we're in list / instanciate object scope
45
+
46
+ @john = person 'John (is a doondy head)' do
47
+ # we instanticated an object, so now we're in attr assignment scope
48
+ age 12 # this is equiv to @john.age = 12
49
+ gripes do # open up a colection on john...
50
+ # now we're back in list / instanticate object scope
51
+ gripe 'untested code' # creating a gripe
52
+ gripe 'no beer' # and another
53
+ end # out of gripes, back to john attr assignment
54
+ end # out of john
55
+
56
+ # we're back to creating people:
57
+
58
+ person 'Ryan' do
59
+ age 25
60
+ end
61
+
62
+ person 'Tim' do
63
+ age 'Infinite'
64
+ chums @john # instance vars are shared across Lumberjack.construct
65
+ end
66
+ end
67
+
68
+ puts tree.inspect
69
+ ```
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rake/testtask'
2
3
 
3
- require 'rspec/core/rake_task'
4
- RSpec::Core::RakeTask.new(:spec) do |s|
5
- s.pattern = '*_spec.rb'
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.pattern = "spec/*_spec.rb"
6
6
  end
7
7
 
8
- task :default => :spec
8
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ person 'John S', 50
2
+ person 'Andrea', 46
3
+ person 'John R', 26
4
+ raise "the roof"
5
+ person 'Sarah', 24
6
+ person 'Ethan', 10
@@ -33,7 +33,7 @@ class Lumberjack
33
33
 
34
34
  def load_tree_file(filename)
35
35
  File.open filename, 'r' do |f|
36
- eval f.read, binding, __FILE__, __LINE__
36
+ eval f.read, binding, filename
37
37
  end
38
38
  end
39
39
 
@@ -1,19 +1,21 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = "lumberjack-dsl"
4
- s.version = "0.0.1"
4
+ s.version = "0.0.3"
5
+ s.license = "MIT"
5
6
  s.authors = ["Ryan Allen", "Steve Hodgkiss", "John Barton", "James Dowling"]
6
7
  s.email = ["ryan@yeahnah.org", "steve@hodgkiss.me", "jrbarton@gmail.com", "jamesd741@gmail.com"]
7
- s.homepage = ""
8
+ s.homepage = "https://github.com/ryan-allen/lumberjack"
8
9
  s.summary = %q{Lumberjack is best summed up as a generic DSL for constructing object trees.}
9
- s.description = %q{}
10
+ s.description = <<-EOS.gsub(/^ /, "")
11
+ Lumberjack is best summed up as a generic DSL for constructing object trees.
10
12
 
11
- s.rubyforge_project = "lumberjack-dsl"
13
+ It works great for configuration files, for generating a tree of configuration objects for later reflection or what-not. But in reality you could use it for whatever you're willing to dream up.
14
+ EOS
12
15
 
13
16
  s.files = `git ls-files`.split("\n")
14
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
- s.require_paths = ["."]
17
-
18
- s.add_development_dependency "rspec"
19
+ s.require_paths = ["lib"]
20
+ s.required_ruby_version = '>= 1.9.3'
19
21
  end
@@ -1,7 +1,6 @@
1
- require 'bundler'
2
- Bundler.require
3
1
  $: << '.'
4
2
  require 'lumberjack'
3
+ require 'minitest/autorun'
5
4
 
6
5
  class Family
7
6
  attr_accessor :name, :members, :heritage
@@ -46,42 +45,42 @@ end
46
45
  describe Lumberjack do
47
46
 
48
47
  it 'construct returns an empty list' do
49
- Lumberjack.construct.should be_empty
48
+ Lumberjack.construct.must_be_empty
50
49
  end
51
-
50
+
52
51
  it 'testcan create a single class' do
53
52
  tree = Lumberjack.construct do
54
53
  family {} # api change w/ scoping requires a block to be passed, otherwise can't tell if you're
55
54
  # trying to resolve a nested scope
56
55
  end
57
- tree.length.should eq 1
58
- tree.first.should be_instance_of Family
56
+ tree.length.must_equal 1
57
+ tree.first.must_be_instance_of Family
59
58
  end
60
-
59
+
61
60
  it 'test can create a single class passing in args' do
62
61
  tree = Lumberjack.construct do
63
62
  family 'Allen', :heritage => :mixed
64
63
  end
65
- tree.length.should eq 1
66
- tree.first.should be_instance_of Family
67
- tree.first.name.should eq 'Allen'
68
- tree.first.heritage.should eq :mixed
64
+ tree.length.must_equal 1
65
+ tree.first.must_be_instance_of Family
66
+ tree.first.name.must_equal 'Allen'
67
+ tree.first.heritage.must_equal :mixed
69
68
  end
70
-
69
+
71
70
  it 'can create two classes passing in args' do
72
71
  tree = Lumberjack.construct do
73
72
  family 'Allen', :heritage => [:english, :irish]
74
73
  family 'Ta\'eed', :heritage => [:iranian, :english]
75
74
  end
76
- tree.length.should eq 2
77
- tree[0].should be_instance_of Family
78
- tree[0].name.should eq 'Allen'
79
- tree[0].heritage.should eq [:english, :irish]
80
- tree[1].should be_instance_of Family
81
- tree[1].name.should eq 'Ta\'eed'
82
- tree[1].heritage.should eq [:iranian, :english]
75
+ tree.length.must_equal 2
76
+ tree[0].must_be_instance_of Family
77
+ tree[0].name.must_equal 'Allen'
78
+ tree[0].heritage.must_equal [:english, :irish]
79
+ tree[1].must_be_instance_of Family
80
+ tree[1].name.must_equal 'Ta\'eed'
81
+ tree[1].heritage.must_equal [:iranian, :english]
83
82
  end
84
-
83
+
85
84
  it 'can set instance members with block' do
86
85
  tree = Lumberjack.construct do
87
86
  family do
@@ -89,24 +88,24 @@ describe Lumberjack do
89
88
  heritage [:english, :irish]
90
89
  end
91
90
  end
92
- tree.length.should eq 1
93
- tree[0].should be_instance_of Family
94
- tree[0].name.should eq 'Allen'
95
- tree[0].heritage.should eq [:english, :irish]
91
+ tree.length.must_equal 1
92
+ tree[0].must_be_instance_of Family
93
+ tree[0].name.must_equal 'Allen'
94
+ tree[0].heritage.must_equal [:english, :irish]
96
95
  end
97
-
96
+
98
97
  it 'can used mixed constructor and instance members in_blocke' do
99
98
  tree = Lumberjack.construct do
100
99
  family 'Allen' do
101
100
  heritage [:english, :irish]
102
101
  end
103
102
  end
104
- tree.length.should eq 1
105
- tree[0].should be_instance_of Family
106
- tree[0].name.should eq 'Allen'
107
- tree[0].heritage.should eq [:english, :irish]
103
+ tree.length.must_equal 1
104
+ tree[0].must_be_instance_of Family
105
+ tree[0].name.must_equal 'Allen'
106
+ tree[0].heritage.must_equal [:english, :irish]
108
107
  end
109
-
108
+
110
109
  it 'create list in scoped instance if block with no args' do
111
110
  tree = Lumberjack.construct do
112
111
  family 'Allen' do
@@ -120,28 +119,28 @@ describe Lumberjack do
120
119
  end
121
120
  end
122
121
  end
123
- tree.length.should eq 1
124
- tree[0].should be_instance_of Family
125
- tree[0].name.should eq 'Allen'
126
- tree[0].heritage.should eq [:english, :irish]
127
- tree[0].members.length.should eq 3
128
- tree[0].members[0].given_name.should eq 'Tim'
129
- tree[0].members[0].age.should eq 58
130
- tree[0].members[1].given_name.should eq 'Jan'
131
- tree[0].members[1].age.should eq 54
132
- tree[0].members[2].given_name.should eq 'Ryan'
133
- tree[0].members[2].age.should eq 24
122
+ tree.length.must_equal 1
123
+ tree[0].must_be_instance_of Family
124
+ tree[0].name.must_equal 'Allen'
125
+ tree[0].heritage.must_equal [:english, :irish]
126
+ tree[0].members.length.must_equal 3
127
+ tree[0].members[0].given_name.must_equal 'Tim'
128
+ tree[0].members[0].age.must_equal 58
129
+ tree[0].members[1].given_name.must_equal 'Jan'
130
+ tree[0].members[1].age.must_equal 54
131
+ tree[0].members[2].given_name.must_equal 'Ryan'
132
+ tree[0].members[2].age.must_equal 24
134
133
  end
135
-
134
+
136
135
  it 'can take generate arrays with comma semantics and tell the difference' do
137
136
  tree = Lumberjack.construct do
138
137
  family 'Allen' do
139
138
  heritage :english, :irish
140
139
  end
141
140
  end
142
- tree[0].heritage.should eq [:english, :irish]
141
+ tree[0].heritage.must_equal [:english, :irish]
143
142
  end
144
-
143
+
145
144
  it 'will_push element onto object if list accessor is already initialized' do
146
145
  vehicles = Lumberjack.construct do
147
146
  vehicle :name => 'unicycle' do
@@ -150,25 +149,25 @@ describe Lumberjack do
150
149
  end
151
150
  end
152
151
  end
153
- vehicles[0].wheels.should be_instance_of SetOfWheels
152
+ vehicles[0].wheels.must_be_instance_of SetOfWheels
154
153
  end
155
-
154
+
156
155
  it 'can set initial context to something else besdies an array' do
157
156
  showroom = Lumberjack.construct Showroom.new do
158
157
  vehicle :name => 'a FERRARRI!!!1'
159
158
  vehicle :name => 'a MASERATI!!!1'
160
159
  vehicle :name => 'a PORCHE OMG!!!'
161
160
  end
162
- showroom.should be_instance_of Showroom
163
- showroom.length.should eq 3
161
+ showroom.must_be_instance_of Showroom
162
+ showroom.length.must_equal 3
164
163
  end
165
-
164
+
166
165
  # biggest hack ever, use a ! to isntanciate a class to an accessor, must be
167
166
  # inferable by the accessor name, such a large hack, but we need it for
168
- # production, and i'm sure other people will need it, so lets leave this
167
+ # production, and i'm sure other people will need it, so lets leave this
169
168
  # gaping flaw of lumberjack for the time being till we can think of something
170
169
  # more nice and appropriate :/ :D
171
- it 'can create instance of class via bang method' do
170
+ it 'can create instance of class via bang method' do
172
171
  cars = Lumberjack.construct do
173
172
  vehicle :name => 'Prius (are owned by rich hippies)' do
174
173
  person! 'Ryan' do # i so put my foot in here, i'm not a rich hippy!
@@ -176,20 +175,20 @@ describe Lumberjack do
176
175
  end
177
176
  end
178
177
  end
179
- eval('Vehicle').should eq Vehicle
180
- cars[0].class.should eq Vehicle
181
- cars[0].name.should eq 'Prius (are owned by rich hippies)'
182
- cars[0].person.should be_instance_of Person
183
- cars[0].person.age.should eq 25
184
- cars[0].person.given_name.should eq 'Ryan'
178
+ eval('Vehicle').must_equal Vehicle
179
+ cars[0].class.must_equal Vehicle
180
+ cars[0].name.must_equal 'Prius (are owned by rich hippies)'
181
+ cars[0].person.must_be_instance_of Person
182
+ cars[0].person.age.must_equal 25
183
+ cars[0].person.given_name.must_equal 'Ryan'
185
184
  end
186
-
185
+
187
186
  it 'can create list of primitives' do # not sure this is valid useage (of course it is you big dummy ryan from the past!)
188
187
  tree = Lumberjack.construct do
189
188
  array [:one, :two, :three]
190
189
  array [:four, :five, :six]
191
190
  end
192
- tree.should eq [[:one, :two, :three], [:four, :five, :six]]
191
+ tree.must_equal [[:one, :two, :three], [:four, :five, :six]]
193
192
  end
194
193
 
195
194
  it 'we got backslashes that resolve scope or something' do
@@ -199,11 +198,11 @@ describe Lumberjack do
199
198
  vehicle/heavy(:name => 'Heavy Car')
200
199
  vehicle/heavy/really_heavy(:name => 'Really Heavy Heavy Car')
201
200
  end
202
- cars[0].should be_instance_of Vehicle
203
- cars[1].should be_instance_of Vehicle::Heavy
204
- cars[2].should be_instance_of Vehicle::Heavy::ReallyHeavy
201
+ cars[0].must_be_instance_of Vehicle
202
+ cars[1].must_be_instance_of Vehicle::Heavy
203
+ cars[2].must_be_instance_of Vehicle::Heavy::ReallyHeavy
205
204
  end
206
-
205
+
207
206
  it 'we can load in other files' do
208
207
  family = Lumberjack.construct do
209
208
  family 'Barton' do
@@ -213,36 +212,53 @@ describe Lumberjack do
213
212
  end
214
213
  end
215
214
  end
216
-
217
- family.length.should eq 1
218
- family.first.should be_instance_of Family
219
- family.first.name.should eq 'Barton'
220
- family.first.heritage.should eq [:dutch, :mongrel_aussie]
221
215
 
222
- family.first.members.size.should eq 5
216
+ family.length.must_equal 1
217
+ family.first.must_be_instance_of Family
218
+ family.first.name.must_equal 'Barton'
219
+ family.first.heritage.must_equal [:dutch, :mongrel_aussie]
220
+
221
+ family.first.members.size.must_equal 5
222
+
223
+ family.first.members.first.given_name.must_equal 'John S'
224
+ family.first.members.first.age.must_equal 50
223
225
 
224
- family.first.members.first.given_name.should eq 'John S'
225
- family.first.members.first.age.should eq 50
226
+ family.first.members.last.given_name.must_equal 'Ethan'
227
+ family.first.members.last.age.must_equal 10
228
+ end
226
229
 
227
- family.first.members.last.given_name.should eq 'Ethan'
228
- family.first.members.last.age.should eq 10
230
+ it 'provides accurate backtrace information when loading in files' do
231
+ begin
232
+ Lumberjack.construct do
233
+ family 'Barton' do
234
+ heritage [:dutch, :mongrel_aussie]
235
+ members do
236
+ load_tree_file 'examples/broken-people.rb'
237
+ end
238
+ end
239
+ end
240
+ raise "the dead"
241
+ rescue
242
+ $!.message.must_equal "the roof"
243
+ $!.backtrace.first.must_equal %{examples/broken-people.rb:4:in `block in load_tree_file'}
244
+ end
229
245
  end
230
-
246
+
231
247
  it 'we can share branches that are defined' do
232
248
  families = Lumberjack.construct do
233
-
249
+
234
250
  shared_branch :kids do
235
251
  person 'Jack', 11
236
252
  person 'Jill', 10
237
253
  end
238
-
254
+
239
255
  family "Dad's new family" do
240
256
  members do
241
257
  person 'Dad', 45
242
258
  graft_branch :kids
243
259
  end
244
260
  end
245
-
261
+
246
262
  family "Mum's new family" do
247
263
  members do
248
264
  person 'Mum', 40
@@ -251,18 +267,18 @@ describe Lumberjack do
251
267
  end
252
268
  end
253
269
  end
254
-
255
- families.length.should eq 2
256
- families[0].should be_instance_of Family
257
- families[1].should be_instance_of Family
258
-
259
- families[0].members.size.should eq 3
260
- families[0].members.any? {|m| m.given_name == 'Jack'}.should be_true
261
- families[0].members.any? {|m| m.given_name == 'Jill'}.should be_true
262
-
263
- families[1].members.size.should eq 4
264
- families[1].members.any? {|m| m.given_name == 'Jack'}.should be_true
265
- families[1].members.any? {|m| m.given_name == 'Jill'}.should be_true
270
+
271
+ families.length.must_equal 2
272
+ families[0].must_be_instance_of Family
273
+ families[1].must_be_instance_of Family
274
+
275
+ families[0].members.size.must_equal 3
276
+ families[0].members.any? {|m| m.given_name == 'Jack'}.must_equal true
277
+ families[0].members.any? {|m| m.given_name == 'Jill'}.must_equal true
278
+
279
+ families[1].members.size.must_equal 4
280
+ families[1].members.any? {|m| m.given_name == 'Jack'}.must_equal true
281
+ families[1].members.any? {|m| m.given_name == 'Jill'}.must_equal true
266
282
  end
267
283
 
268
284
  it 'we can remove twigs with prune' do
@@ -292,20 +308,20 @@ describe Lumberjack do
292
308
  end
293
309
  end
294
310
 
295
- families[0].members.any? {|m| m.given_name == 'Will' && m.age == 11}.should be_true
296
- families[0].members.any? {|m| m.given_name == 'Jack' && m.age == 12}.should be_true
297
- families[0].members.any? {|m| m.given_name == 'Mum' && m.age == 26}.should be_true
298
- families[0].members.any? {|m| m.given_name == 'Dad' && m.age == 45}.should be_true
311
+ families[0].members.any? {|m| m.given_name == 'Will' && m.age == 11}.must_equal true
312
+ families[0].members.any? {|m| m.given_name == 'Jack' && m.age == 12}.must_equal true
313
+ families[0].members.any? {|m| m.given_name == 'Mum' && m.age == 26}.must_equal true
314
+ families[0].members.any? {|m| m.given_name == 'Dad' && m.age == 45}.must_equal true
299
315
  end
300
-
316
+
301
317
  it 'doesnt share branches that are undefined' do
302
318
  # TODO: why does this output funny stuff
303
- expect {
319
+ lambda {
304
320
  Lumberjack.construct do
305
321
  family 'wont work' do
306
322
  graft_branch :non_existant
307
323
  end
308
324
  end
309
- }.to raise_error RuntimeError
325
+ }.must_raise RuntimeError
310
326
  end
311
327
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lumberjack-dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 0.0.3
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ryan Allen
@@ -12,20 +11,12 @@ authors:
12
11
  autorequire:
13
12
  bindir: bin
14
13
  cert_chain: []
15
- date: 2012-03-13 00:00:00.000000000 Z
16
- dependencies:
17
- - !ruby/object:Gem::Dependency
18
- name: rspec
19
- requirement: &70259449806300 !ruby/object:Gem::Requirement
20
- none: false
21
- requirements:
22
- - - ! '>='
23
- - !ruby/object:Gem::Version
24
- version: '0'
25
- type: :development
26
- prerelease: false
27
- version_requirements: *70259449806300
28
- description: ''
14
+ date: 2015-10-23 00:00:00.000000000 Z
15
+ dependencies: []
16
+ description: |
17
+ Lumberjack is best summed up as a generic DSL for constructing object trees.
18
+
19
+ It works great for configuration files, for generating a tree of configuration objects for later reflection or what-not. But in reality you could use it for whatever you're willing to dream up.
29
20
  email:
30
21
  - ryan@yeahnah.org
31
22
  - steve@hodgkiss.me
@@ -35,38 +26,39 @@ executables: []
35
26
  extensions: []
36
27
  extra_rdoc_files: []
37
28
  files:
38
- - .gitignore
39
- - .rspec
40
- - Gemfile
29
+ - ".gitignore"
30
+ - ".rspec"
41
31
  - MIT-LICENSE
42
32
  - README.markdown
43
33
  - Rakefile
34
+ - examples/broken-people.rb
44
35
  - examples/people.rb
36
+ - lib/lumberjack.rb
45
37
  - lumberjack.gemspec
46
- - lumberjack.rb
47
- - lumberjack_spec.rb
48
- homepage: ''
49
- licenses: []
38
+ - spec/lumberjack_spec.rb
39
+ homepage: https://github.com/ryan-allen/lumberjack
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
50
43
  post_install_message:
51
44
  rdoc_options: []
52
45
  require_paths:
53
- - .
46
+ - lib
54
47
  required_ruby_version: !ruby/object:Gem::Requirement
55
- none: false
56
48
  requirements:
57
- - - ! '>='
49
+ - - ">="
58
50
  - !ruby/object:Gem::Version
59
- version: '0'
51
+ version: 1.9.3
60
52
  required_rubygems_version: !ruby/object:Gem::Requirement
61
- none: false
62
53
  requirements:
63
- - - ! '>='
54
+ - - ">="
64
55
  - !ruby/object:Gem::Version
65
56
  version: '0'
66
57
  requirements: []
67
- rubyforge_project: lumberjack-dsl
68
- rubygems_version: 1.8.11
58
+ rubyforge_project:
59
+ rubygems_version: 2.4.5.1
69
60
  signing_key:
70
- specification_version: 3
61
+ specification_version: 4
71
62
  summary: Lumberjack is best summed up as a generic DSL for constructing object trees.
72
- test_files: []
63
+ test_files:
64
+ - spec/lumberjack_spec.rb
data/Gemfile DELETED
@@ -1,3 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem "rspec"