pickle-dupe 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -2,15 +2,20 @@
2
2
 
3
3
  Pickle-dupe is an add-on to pickle that works with Dupe, an Active Resource mocking/factory.
4
4
 
5
- == Note on Patches/Pull Requests
6
-
7
- * Fork the project.
8
- * Make your feature addition or bug fix.
9
- * Add tests for it. This is important so I don't break it in a
10
- future version unintentionally.
11
- * Commit, do not mess with rakefile, version, or history.
12
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
- * Send me a pull request. Bonus points for topic branches.
5
+ == Installation
6
+
7
+ Pickle-dupe requires the following gems
8
+ * pickle
9
+ * dupe
10
+
11
+ To install pickle-dupe gem, do:
12
+ sudo gem install pickle-dupe
13
+
14
+ == Usage
15
+ In order to use pickle with dupe, you need to add :dupe to your pickle's configuration as follows:
16
+ Pickle.configure do |config|
17
+ config.adapters = [:dupe]
18
+ end
14
19
 
15
20
  == Copyright
16
21
 
data/Rakefile CHANGED
@@ -11,6 +11,7 @@ begin
11
11
  gem.homepage = "http://github.com/iawgens/pickle-dupe"
12
12
  gem.authors = ["iawgens"]
13
13
  gem.add_dependency "pickle",">=0.2.1"
14
+ gem.add_dependency "dupe",">=0.4.8"
14
15
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
16
  end
16
17
  Jeweler::GemcutterTasks.new
@@ -28,8 +29,8 @@ end
28
29
  begin
29
30
  require 'rcov/rcovtask'
30
31
  Rcov::RcovTask.new do |test|
31
- test.libs << 'test'
32
- test.pattern = 'test/**/test_*.rb'
32
+ test.libs << 'spec'
33
+ test.pattern = 'spec/**/*_spec.rb'
33
34
  test.verbose = true
34
35
  end
35
36
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -1,8 +1,12 @@
1
1
  class AbstractResource < ActiveResource::Base
2
2
  self.site = ''
3
3
  end
4
+
4
5
  class Recipe < AbstractResource
5
6
  end
6
7
 
7
8
  class Ingredient < AbstractResource
9
+ end
10
+
11
+ class Step < AbstractResource
8
12
  end
@@ -11,19 +11,24 @@ Dupe.define :recipe do |recipe|
11
11
  Dupe.next :recipe_title
12
12
  end
13
13
 
14
- # recipe.ingredients do |ingredients|
15
- # ingredients.split(', ').map do |ingredient|
16
- # Dupe.find(:ingredient) do |i|
17
- # i.label == labelize(ingredient)
18
- # end
19
- # end
20
- # end
14
+ # has_many ingredients
15
+ recipe.ingredients []
16
+
17
+ # has_many steps
18
+ recipe.steps []
21
19
 
22
20
  recipe.after_create do |r|
23
21
  r.label = labelize(r.title)
24
22
  end
25
23
  end
26
24
 
25
+ Dupe.define :step do |step|
26
+ step.uniquify :title
27
+
28
+ step.after_create do |s|
29
+ s.label = labelize(s.title)
30
+ end
31
+ end
27
32
 
28
33
  # Not Applicable in Dupe
29
34
  # Dupe.define :fancy_recipe, :class => Recipe do |t|
@@ -33,6 +38,9 @@ end
33
38
  Dupe.define :ingredient do |ingredient|
34
39
  ingredient.uniquify :name
35
40
 
41
+ #belongs_to_many recipes
42
+ ingredient.recipes []
43
+
36
44
  ingredient.after_create do |i|
37
45
  i.label = labelize(i.name)
38
46
  end
@@ -6,7 +6,8 @@ Feature: I can easily create models from dupe
6
6
  Scenario: I create a recipe, and see if it looks right
7
7
  Given a recipe exists
8
8
  Then a recipe should exist
9
-
9
+
10
+ @basic_test
10
11
  Scenario: I create a recipe with specific name, and see if it looks right
11
12
  Given a recipe exists with name: "Chicken Recipe"
12
13
  Then a recipe should exist with name: "Chicken Recipe"
@@ -14,31 +15,45 @@ Feature: I can easily create models from dupe
14
15
  Scenario: I create stub recipes, and see if it looks right
15
16
  Given 3 recipes exist
16
17
  Then 3 recipes should exist
17
-
18
- Scenario: I create some recipes, and some ingredients
18
+
19
+ @many_to_one_association
20
+ Scenario: I create some recipes, and some steps
19
21
  Given a recipe: "one" exists
20
- And an ingredient exists with recipe: recipe "one"
21
- And another ingredient exists with recipe: recipe "one"
22
+ And a step exists with recipe: recipe "one"
23
+ And another step exists with recipe: recipe "one"
22
24
  And a recipe: "two" exists
23
- And an ingredient exists with recipe: recipe "two"
24
-
25
- # TODO: GC 02/05/2010 named factory definition is not yet supported by dupe
25
+ And a step exists with recipe: recipe "two"
26
+
27
+ # TODO: GC 02/05/2010 named factory definition is not yet supported by dupe
26
28
  # And a fancy recipe exists
27
29
  # And an ingredient exists with recipe: the fancy recipe
30
+
31
+ # testing custom step
32
+ Then the first step should be step of the recipe: "one"
33
+ And the 2nd step should be step of recipe "one"
34
+ And the last step should be step of recipe "two"
28
35
 
29
- Then the first ingredient should be ingredient of the recipe: "one"
30
- And the 2nd ingredient should be the ingredient of recipe "one"
31
- And the last ingredient should be the recipe of recipe "two"
32
-
33
- Then the first ingredient should be in recipe "one"'s ingredients
34
- And the 2nd ingredient should be in recipe: "one"'s ingredients
35
- And the last ingredient should be in recipe "two"'s ingredients
36
- And recipe "two" should be the last ingredient's recipe
36
+ Then the first step should be in recipe "one"'s steps
37
+ And the 2nd step should be in recipe: "one"'s steps
38
+ And the last step should be in recipe "two"'s steps
39
+ And recipe "two" should be the last step's recipe
37
40
 
38
- But the first ingredient should not be in the fancy recipe's ingredients
39
- And the last ingredient should not be in recipe "one"'s ingredients
40
- And the fancy recipe should not be the first ingredient's recipe
41
-
41
+ #But the first ingredient should not be in the fancy recipe's ingredients
42
+ But the last step should not be in recipe "one"'s steps
43
+ And recipe "two" should not be the first step's recipe
44
+ #And the fancy recipe should not be the first ingredient's recipe
45
+
46
+ @many_to_many_association
47
+ Scenario: I create some ingredients and associate to some recipe
48
+ Given an ingredient: "one" exists
49
+ And an ingredient: "two" exists
50
+ And a recipe exists with ingredients: ingredient "one"
51
+ And a recipe exists with ingredients: [ingredient "one", ingredient "two"]
52
+ Then the first recipe should be in ingredient "one"'s recipes
53
+ And the last recipe should be in ingredient "one"'s recipes
54
+ And the last recipe should be in ingredient "two"'s recipes
55
+ And the first recipe should not be in ingredient "two"'s recipes
56
+
42
57
  Scenario: Create an ingredient and a recipe refs in a table
43
58
  Given 2 recipes exist
44
59
  And the following ingredients exist:
@@ -1,6 +1,6 @@
1
1
  # this file generated by script/generate pickle
2
2
 
3
- # create a model
3
+ # create a model
4
4
  Given(/^#{capture_model} exists?(?: with #{capture_fields})?$/) do |name, fields|
5
5
  create_model(name, fields)
6
6
  end
@@ -1,4 +1,6 @@
1
1
  # example of making your own matcher with the pickle backend
2
- Then(/^#{capture_model} should be ingredient of #{capture_model}$/) do |ingredient, recipe|
3
- model(recipe).ingredients.should include(model(ingredient))
4
- end
2
+ Then(/^#{capture_model} should be step of #{capture_model}$/) do |step, recipe|
3
+ model(recipe).steps.should include(model(step))
4
+ end
5
+
6
+ # ((?:(?:\w+: (?:(?:(?:I|killah fork)|(?:(?:a|an|another|the|that) )?(?:(?:(?:(?:first|last|(?:\d+(?:st|nd|rd|th))) )?(?:step|recipe|ingredient))|(?:(?:step|recipe|ingredient)(?::? "(?:[^\"]|\.)*"))))|(?:"(?:[^\"]|\.)*"|nil|true|false|[+-]?\d+(?:\.\d+)?))), )*(?:\w+: (?:(?:(?:I|killah fork)|(?:(?:a|an|another|the|that) )?(?:(?:(?:(?:first|last|(?:\d+(?:st|nd|rd|th))) )?(?:step|recipe|ingredient))|(?:(?:step|recipe|ingredient)(?::? "(?:[^\"]|\.)*"))))|(?:"(?:[^\"]|\.)*"|nil|true|false|[+-]?\d+(?:\.\d+)?))))
@@ -21,8 +21,100 @@ module Pickle
21
21
  end
22
22
 
23
23
  def create(attrs = {})
24
- ::Dupe.create(@name, attrs)
24
+ duped_object = ::Dupe.create(@name, attrs)
25
+ assign_missing_associations(duped_object, attrs) unless attrs.blank?
26
+
27
+ return duped_object
25
28
  end
29
+
30
+ private
31
+
32
+ # Since ActiveResource does not have the notion of relationship between models, when associating
33
+ # a duped object to another object, Dupe does not take care of the association in both ways.
34
+ #
35
+ # Consider the following example with Recipe and DirectionStep. A recipe has many direction_steps
36
+ # and a direction_step belongs to one recipe. To setup dupe data for the cucumber scenario, we do the following:
37
+ #
38
+ # @recipe = Dupe.create :recipe #=> <#Duped::Recipe id=1>
39
+ # @direction_step = Dupe.create(:direction_step, {:recipe => @recipe})
40
+ # #=> <#Duped:DirectionStep recipe=<#Duped::Recipe id=1> id=1>
41
+ #
42
+ # That would associate the duped recipe to the duped ingredient. However, the duped recipe has
43
+ # no knowledge of the direction_step.
44
+ #
45
+ # @recipe.direction_steps #=> nil
46
+ #
47
+ # Since Dupe does not handle the reverse association, this method thus assign the association to the
48
+ # has_many side when a duped object is assigned to the belongs_to side when using pickle steps.
49
+ #
50
+ # To implement this association, you must let Dupe knows that a has_many association is expected by defining
51
+ # it in dupe definition as follows:
52
+ #
53
+ # Dupe.define :recipe do |recipe|
54
+ # recipe.direction_steps []
55
+ # end
56
+ #
57
+ # Once defined, when you call a pickle step to assign a belongs_to association, like:
58
+ #
59
+ # Given a recipe: "one" exists
60
+ # And a direction step exists with recipe: recipe "one"
61
+ #
62
+ # Then the "Then" step would be able to get the direction steps through the recipe duped object, like:
63
+ #
64
+ # Then the first direction step should be in recipe "one"'s direction steps
65
+ #
66
+ # This hack took care of has side when assigning to belongs_to side when it's a many_to_one:
67
+ #
68
+ # Dupe.create :direction_step, {:recipe => recipe}
69
+ #
70
+ # but does not take care of the many_to_many relationship like:
71
+ #
72
+ # Dupe.create :recipe, {:ingredients => [<Duped::Ingredient>,<Duped::Ingredient>]}
73
+ #
74
+ def assign_missing_associations(duped_object, attrs)
75
+ association_objects = collect_association_objects(attrs)
76
+ association_objects.each {|association_object|
77
+
78
+ # When a pickle step causes Dupe to do the following:
79
+ #
80
+ # Dupe.create(:direction_step, :recipe => @recipe)
81
+ #
82
+ # Then duped_object would be of class Dupe::DirectionStep and association_object would be of
83
+ # class Dupe::Recipe.
84
+ #
85
+ if association_object.kind_of?(Array)
86
+ association_object.each {|a|
87
+ assign_association(a, duped_object)
88
+ }
89
+ else
90
+ assign_association(association_object, duped_object)
91
+ end
92
+ }
93
+ end
94
+
95
+ def assign_association(association_object, duped_object)
96
+ has_one_association = duped_object.__model__.name #=> :direction_step
97
+ has_many_association = has_one_association.to_s.pluralize.to_sym #=> :direction_steps
98
+
99
+ # The following would check for the existence of the key :direction_steps
100
+ # in the duped recipe's definition
101
+ if association_object.__model__.schema.attribute_templates.keys.include?(has_many_association)
102
+ association_object[has_many_association] << duped_object
103
+ else #assume it's a has_one association
104
+ association_object[has_one_association] = duped_object
105
+ end
106
+ end
107
+
108
+ # Selecting association objects from the attributes hash and return as array. Association objects are of class
109
+ # Dupe::Database::Record
110
+ # Given :association => <#Duped::Ingredient name="ingredient 1 name" recipes=[] label="ingredient-1-name" id=1> or
111
+ # :association => [<#Duped...>] will return [[<#Duped...>,<#Duped...>],<#Duped...>]
112
+ def collect_association_objects(attrs)
113
+ attrs.select {|k,v|
114
+ v.kind_of?(Array) || v.kind_of?(::Dupe::Database::Record)
115
+ }.collect {|i| i[1]}
116
+ end
117
+
26
118
  end
27
119
 
28
120
  end
@@ -0,0 +1,56 @@
1
+ module Pickle
2
+ class Parser
3
+ def parse_field_with_multi_values(field)
4
+ # Would handle multiple values like "ingredients: [ingredient \"one\", ingredient \"two"\]"
5
+ if session && field =~ /^(\w+): #{match_model_in_values}$/
6
+ field_key = $1
7
+
8
+ models = []
9
+ values = parse_values(field)
10
+ values.each do |value|
11
+ if value =~ /^#{capture_model}$/
12
+ models << session.model($1)
13
+ end
14
+ end
15
+
16
+ {field_key => models}
17
+ else
18
+ parse_field_without_multi_values(field)
19
+ end
20
+
21
+ end
22
+
23
+ alias_method_chain :parse_field, :multi_values
24
+
25
+ def match_field
26
+ "(?:\\w+: #{match_values})"
27
+ end
28
+
29
+ def match_value
30
+ "(?:#{match_model}|\"#{match_quoted}\"|nil|true|false|[+-]?\\d+(?:\\.\\d+)?)"
31
+ end
32
+
33
+ def match_values
34
+ # like [step "one", step "two"]
35
+ "(?:\\[?(?:#{match_value}, )*#{match_value}\\]?)"
36
+ end
37
+
38
+ def match_model_in_values
39
+ "\\[(?:#{match_model}, )*#{match_model}\\]"
40
+ end
41
+
42
+ private
43
+
44
+ # Given field of "ingredients: [ingredient \"one\", ingredient \"two\"]" return
45
+ # ["ingredient \"one\"","ingredient \"two\""]
46
+ def parse_values(field)
47
+ if field =~ /^\w+: (#{match_values})$/
48
+ $1.scan(/(#{match_value})(?:,|$|\])/).inject([]) do |m, match|
49
+ m << match[0]
50
+ end
51
+ #TODO GC 02/26/2010 - What to do if it does not match the values pattern?
52
+ end
53
+ end
54
+
55
+ end
56
+ end
data/lib/pickle_dupe.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  require 'pickle'
2
2
  require 'pickle_dupe/adapter'
3
3
  require 'pickle_dupe/session'
4
+ require 'pickle_dupe/parser'
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pickle-dupe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - iawgens
@@ -9,19 +14,37 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-08 00:00:00 -05:00
17
+ date: 2010-03-01 00:00:00 -05:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: pickle
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 2
30
+ - 1
23
31
  version: 0.2.1
24
- version:
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: dupe
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 4
44
+ - 8
45
+ version: 0.4.8
46
+ type: :runtime
47
+ version_requirements: *id002
25
48
  description: Dupe is Active Resource mocking/factory for use with cucumber. Pickle-dupe is a pickle add-on that works with Dupe
26
49
  email: gary.s.cheong@gmail.com
27
50
  executables: []
@@ -51,10 +74,8 @@ files:
51
74
  - features/support/pickle_dupe_app.rb
52
75
  - lib/pickle_dupe.rb
53
76
  - lib/pickle_dupe/adapter.rb
77
+ - lib/pickle_dupe/parser.rb
54
78
  - lib/pickle_dupe/session.rb
55
- - spec/pickle_dupe_spec.rb
56
- - spec/spec.opts
57
- - spec/spec_helper.rb
58
79
  has_rdoc: true
59
80
  homepage: http://github.com/iawgens/pickle-dupe
60
81
  licenses: []
@@ -68,21 +89,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
89
  requirements:
69
90
  - - ">="
70
91
  - !ruby/object:Gem::Version
92
+ segments:
93
+ - 0
71
94
  version: "0"
72
- version:
73
95
  required_rubygems_version: !ruby/object:Gem::Requirement
74
96
  requirements:
75
97
  - - ">="
76
98
  - !ruby/object:Gem::Version
99
+ segments:
100
+ - 0
77
101
  version: "0"
78
- version:
79
102
  requirements: []
80
103
 
81
104
  rubyforge_project:
82
- rubygems_version: 1.3.5
105
+ rubygems_version: 1.3.6
83
106
  signing_key:
84
107
  specification_version: 3
85
108
  summary: Pickle that works with Dupe, an Active Resource mocking/factory
86
- test_files:
87
- - spec/pickle_dupe_spec.rb
88
- - spec/spec_helper.rb
109
+ test_files: []
110
+
@@ -1,7 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "PickleDupe" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
6
- end
7
- end
data/spec/spec.opts DELETED
@@ -1 +0,0 @@
1
- --color
data/spec/spec_helper.rb DELETED
@@ -1,9 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
- require 'pickle-dupe'
4
- require 'spec'
5
- require 'spec/autorun'
6
-
7
- Spec::Runner.configure do |config|
8
-
9
- end