pickle-dupe 0.1.0 → 0.2.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/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