dupe 0.4.5 → 0.4.6
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/README.rdoc +35 -12
- data/lib/dupe/dupe.rb +20 -1
- data/lib/dupe/sequence.rb +11 -3
- data/spec/lib_specs/dupe_spec.rb +53 -0
- data/spec/lib_specs/sequence_spec.rb +14 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -4,11 +4,10 @@ There are lots of great tools out there to ease the burden of prototyping Active
|
|
4
4
|
|
5
5
|
But what about prototyping ActiveResource records? That's where Dupe steps in.
|
6
6
|
|
7
|
-
|
8
7
|
== Motivation
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
If you're going to create a service-oriented rails app with ActiveResource, why not cuke the front end first?
|
10
|
+
Let the behavior of the front-end drive the services you build on the backend. That's exactly what Dupe makes possible.
|
12
11
|
|
13
12
|
== Installation
|
14
13
|
|
@@ -18,7 +17,7 @@ If you want to install this for use in something other than a rails project, sim
|
|
18
17
|
|
19
18
|
If you're going to use this in a rails project, add this to your cucumber.rb environment (config/environments/cucumber.rb)
|
20
19
|
|
21
|
-
config.gem 'dupe'
|
20
|
+
config.gem 'dupe'
|
22
21
|
|
23
22
|
Then run this rake task to install the gem:
|
24
23
|
|
@@ -124,17 +123,15 @@ Notice that by using the plural form of the model name, we ensure that we receiv
|
|
124
123
|
|
125
124
|
==Finding or Creating Resources
|
126
125
|
|
127
|
-
You might have seen this one coming
|
126
|
+
You might have seen this one coming.
|
127
|
+
|
128
|
+
Let's assume no genres currently exist. If we call the "find_or_create" method, it will create a new :genre.
|
128
129
|
|
129
|
-
irb# Dupe.find :genre
|
130
|
-
Dupe::Database::TableDoesNotExistError: The table ':genre' does not exist.
|
131
|
-
from /Library/Ruby/Gems/1.8/gems/dupe-0.4.0/lib/dupe/database.rb:30:in `select'
|
132
|
-
from /Library/Ruby/Gems/1.8/gems/dupe-0.4.0/lib/dupe/dupe.rb:295:in `find'
|
133
|
-
from (irb):40
|
134
|
-
|
135
130
|
irb# Dupe.find_or_create :genre
|
136
131
|
==> <#Duped::Genre id=1>
|
137
132
|
|
133
|
+
If we call it again, it will find the :genre we already created:
|
134
|
+
|
138
135
|
irb# Dupe.find_or_create :genre
|
139
136
|
==> <#Duped::Genre id=1>
|
140
137
|
|
@@ -263,7 +260,7 @@ Now, let's create a book:
|
|
263
260
|
|
264
261
|
=== Uniquify attributes
|
265
262
|
|
266
|
-
If you'd just like to make sure that some attributes get a unique value
|
263
|
+
If you'd just like to make sure that some attributes get a unique value, then you can use the uniquify
|
267
264
|
method:
|
268
265
|
|
269
266
|
irb# Dupe.define :book do |attrs|
|
@@ -280,6 +277,29 @@ any records it creates:
|
|
280
277
|
==> <#Duped::Book author="book 2 author" title="Rooby" genre="book 2 genre" id=2>
|
281
278
|
|
282
279
|
|
280
|
+
=== Sequences
|
281
|
+
|
282
|
+
The "uniquify" method is great if don't care too much about the format of the values it creates. But what if you'd like to ensure
|
283
|
+
that the value of an attribute conforms to a specific format?
|
284
|
+
|
285
|
+
irb# Dupe.sequence :email do |n|
|
286
|
+
--# "email-#{n}@somewhere.com"
|
287
|
+
--# end
|
288
|
+
|
289
|
+
irb# Dupe.define :user do |user|
|
290
|
+
--# user.uniquify :name
|
291
|
+
--# user.email do
|
292
|
+
--# Dupe.next :email
|
293
|
+
--# end
|
294
|
+
--# end
|
295
|
+
|
296
|
+
irb# Dupe.create :user
|
297
|
+
==> <#Duped::User name="user 1 name" id=1 email="email-1@somewhere.com">
|
298
|
+
|
299
|
+
irb# Dupe.create :user
|
300
|
+
==> <#Duped::User name="user 2 name" id=2 email="email-2@somewhere.com">
|
301
|
+
|
302
|
+
|
283
303
|
=== Callbacks
|
284
304
|
|
285
305
|
Suppose we'd like to make sure that our books get a unique label. We can accomplish that with an after_create callback:
|
@@ -302,6 +322,9 @@ Suppose we'd like to make sure that our books get a unique label. We can accompl
|
|
302
322
|
==> <#Duped::Book author=nil label="rooby-on-rails--1" title="Rooby on Rails" publish_date=nil id=1 isbn=842518>
|
303
323
|
|
304
324
|
|
325
|
+
|
326
|
+
|
327
|
+
|
305
328
|
= ActiveResource
|
306
329
|
|
307
330
|
So how does Dupe actually help us to spec/test ActiveResource-based applications? It uses a simple, yet sophisticated "intercept-mocking" technique, whereby failed network requests sent by ActiveResource fallback to the "Duped" network. Consider the following:
|
data/lib/dupe/dupe.rb
CHANGED
@@ -5,6 +5,7 @@ class Dupe
|
|
5
5
|
class << self
|
6
6
|
|
7
7
|
attr_reader :models #:nodoc:
|
8
|
+
attr_reader :sequences #:nodoc:
|
8
9
|
attr_reader :database #:nodoc:
|
9
10
|
|
10
11
|
# set this to "true" if you Dupe to spit out mocked requests
|
@@ -385,6 +386,15 @@ class Dupe
|
|
385
386
|
results
|
386
387
|
end
|
387
388
|
end
|
389
|
+
|
390
|
+
def sequence(name, &block)
|
391
|
+
sequences[name.to_sym] = Sequence.new 1, block
|
392
|
+
end
|
393
|
+
|
394
|
+
def next(name)
|
395
|
+
raise ArgumentError, "Unknown sequence \":#{name}\"" unless sequences.has_key?(name)
|
396
|
+
sequences[name].next
|
397
|
+
end
|
388
398
|
|
389
399
|
def models #:nodoc:
|
390
400
|
@models ||= {}
|
@@ -397,14 +407,23 @@ class Dupe
|
|
397
407
|
def database #:nodoc:
|
398
408
|
@database ||= Dupe::Database.new
|
399
409
|
end
|
410
|
+
|
411
|
+
def sequences #:nodoc:
|
412
|
+
@sequences ||= {}
|
413
|
+
end
|
400
414
|
|
401
|
-
# clears out all model definitions and database records / tables.
|
415
|
+
# clears out all model definitions, sequences, and database records / tables.
|
402
416
|
def reset
|
403
417
|
reset_models
|
404
418
|
reset_database
|
405
419
|
reset_network
|
420
|
+
reset_sequences
|
406
421
|
end
|
407
422
|
|
423
|
+
def reset_sequences
|
424
|
+
@sequences = {}
|
425
|
+
end
|
426
|
+
|
408
427
|
def reset_models
|
409
428
|
@models = {}
|
410
429
|
end
|
data/lib/dupe/sequence.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
class Sequence #:nodoc:
|
2
2
|
attr_reader :current_value
|
3
3
|
|
4
|
-
def initialize(starting_at=1)
|
4
|
+
def initialize(starting_at=1, sequencer=nil)
|
5
5
|
@current_value = starting_at
|
6
|
+
if sequencer && sequencer.arity != 1
|
7
|
+
raise ArgumentError, "Your block must accept a single parameter"
|
8
|
+
end
|
9
|
+
@transformer = sequencer
|
6
10
|
end
|
7
11
|
|
8
12
|
def next
|
9
13
|
@current_value += 1
|
10
|
-
@
|
14
|
+
if @transformer
|
15
|
+
@transformer.call(@current_value - 1)
|
16
|
+
else
|
17
|
+
@current_value - 1
|
18
|
+
end
|
11
19
|
end
|
12
|
-
end
|
20
|
+
end
|
data/spec/lib_specs/dupe_spec.rb
CHANGED
@@ -5,14 +5,67 @@ describe Dupe do
|
|
5
5
|
Dupe.reset
|
6
6
|
end
|
7
7
|
|
8
|
+
describe "#sequences" do
|
9
|
+
it "should be empty on initialization" do
|
10
|
+
Dupe.sequences.should == {}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#sequence" do
|
15
|
+
it "should require a sequence name and a block" do
|
16
|
+
proc {Dupe.sequence}.should raise_error(ArgumentError)
|
17
|
+
proc {Dupe.sequence :name}.should_not raise_error
|
18
|
+
proc {Dupe.sequence(:name) {}}.should raise_error(ArgumentError, "Your block must accept a single parameter")
|
19
|
+
proc {Dupe.sequence(:name) {|n| n}}.should_not raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should store the sequence in a sequences hash" do
|
23
|
+
Dupe.sequences.should be_empty
|
24
|
+
|
25
|
+
Dupe.sequence :email do |n|
|
26
|
+
"email-#{n}@address.com"
|
27
|
+
end
|
28
|
+
|
29
|
+
Dupe.sequences.should_not be_empty
|
30
|
+
Dupe.sequences.keys.include?(:email).should == true
|
31
|
+
Dupe.sequences[:email].should be_kind_of(Sequence)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#next" do
|
36
|
+
it "should require a sequence name" do
|
37
|
+
Dupe.sequence :email do |n|
|
38
|
+
"email-#{n}@address.com"
|
39
|
+
end
|
40
|
+
|
41
|
+
proc {Dupe.next}.should raise_error(ArgumentError)
|
42
|
+
proc {Dupe.next :title}.should raise_error(ArgumentError, 'Unknown sequence ":title"')
|
43
|
+
Dupe.next(:email).should == "email-1@address.com"
|
44
|
+
Dupe.next(:email).should == "email-2@address.com"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
8
48
|
describe "reset" do
|
9
49
|
it "should call reset_models, reset_database, and reset_network" do
|
10
50
|
Dupe.should_receive(:reset_models).once
|
11
51
|
Dupe.should_receive(:reset_database).once
|
12
52
|
Dupe.should_receive(:reset_network).once
|
53
|
+
Dupe.should_receive(:reset_sequences).once
|
13
54
|
Dupe.reset
|
14
55
|
end
|
15
56
|
end
|
57
|
+
|
58
|
+
describe "reset_sequences" do
|
59
|
+
it "should reset the sequences to an empty hash" do
|
60
|
+
Dupe.sequences.should == {}
|
61
|
+
Dupe.sequence :email do |n|
|
62
|
+
n
|
63
|
+
end
|
64
|
+
Dupe.sequences.should_not be_empty
|
65
|
+
Dupe.reset_sequences
|
66
|
+
Dupe.sequences.should == {}
|
67
|
+
end
|
68
|
+
end
|
16
69
|
|
17
70
|
describe "reset_models" do
|
18
71
|
it "should reset @models to an empty hash" do
|
@@ -6,6 +6,14 @@ describe Sequence do
|
|
6
6
|
Sequence.new.current_value.should == 1
|
7
7
|
Sequence.new(500).current_value.should == 500
|
8
8
|
end
|
9
|
+
|
10
|
+
it "should accept a block that takes a single parameter" do
|
11
|
+
proc {Sequence.new 1, proc {}}.should raise_error(ArgumentError, "Your block must accept a single parameter")
|
12
|
+
proc {Sequence.new 1, proc {|n| n}}.should_not raise_error
|
13
|
+
proc {Sequence.new 1, proc {|n,m| n}}.should raise_error(ArgumentError, "Your block must accept a single parameter")
|
14
|
+
s = Sequence.new 1, proc {|n| "email-#{n}@address.com"}
|
15
|
+
s.current_value.should == 1
|
16
|
+
end
|
9
17
|
end
|
10
18
|
|
11
19
|
describe "next" do
|
@@ -21,6 +29,11 @@ describe Sequence do
|
|
21
29
|
s.current_value.should == 501
|
22
30
|
s.next.should == 501
|
23
31
|
s.current_value.should == 502
|
32
|
+
|
33
|
+
s = Sequence.new 1, proc {|n| "email-#{n}@address.com"}
|
34
|
+
s.next.should == "email-1@address.com"
|
35
|
+
s.next.should == "email-2@address.com"
|
36
|
+
s.current_value.should == 3
|
24
37
|
end
|
25
38
|
end
|
26
|
-
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dupe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Parker
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-31 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|