ianwhite-pickle 0.1.1 → 0.1.2

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,75 @@
1
+ module Pickle
2
+ class Parser
3
+ module Matchers
4
+ def match_ordinal
5
+ '(?:\d+(?:st|nd|rd|th))'
6
+ end
7
+
8
+ def match_index
9
+ "(?:first|last|#{match_ordinal})"
10
+ end
11
+
12
+ def match_prefix
13
+ '(?:(?:1|a|an|another|the|that) )'
14
+ end
15
+
16
+ def match_quoted
17
+ '(?:[^\\"]|\\.)*'
18
+ end
19
+
20
+ def match_label
21
+ "(?::? \"#{match_quoted}\")"
22
+ end
23
+
24
+ def match_field
25
+ "(?:\\w+: \"#{match_quoted}\")"
26
+ end
27
+
28
+ def match_fields
29
+ "(?:#{match_field}, )*#{match_field}"
30
+ end
31
+
32
+ def match_mapping
33
+ config.mappings.any? ? "(?:#{config.mappings.map(&:search).join('|')})" : ""
34
+ end
35
+
36
+ def match_factory
37
+ "(?:#{config.factory_names.map{|n| n.gsub('_','[_ ]')}.join('|')})"
38
+ end
39
+
40
+ def match_indexed_model
41
+ "(?:(?:#{match_index} )?#{match_factory})"
42
+ end
43
+
44
+ def match_labeled_model
45
+ "(?:#{match_factory}#{match_label})"
46
+ end
47
+
48
+ def match_model
49
+ "(?:#{match_mapping}|#{match_prefix}?(?:#{match_indexed_model}|#{match_labeled_model}))"
50
+ end
51
+
52
+ # create capture analogues of match methods
53
+ instance_methods.select{|m| m =~ /^match_/}.each do |method|
54
+ eval <<-end_eval
55
+ def #{method.sub('match_', 'capture_')} # def capture_field
56
+ "(" + #{method} + ")" # "(" + match_field + ")"
57
+ end # end
58
+ end_eval
59
+ end
60
+
61
+ # special capture methods
62
+ def capture_number_in_ordinal
63
+ '(?:(\d+)(?:st|nd|rd|th))'
64
+ end
65
+
66
+ def capture_name_in_label
67
+ "(?::? \"(#{match_quoted})\")"
68
+ end
69
+
70
+ def capture_key_and_value_in_field
71
+ "(?:(\\w+): \"(#{match_quoted})\")"
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ module Pickle
2
+ class Parser
3
+ # add ability to parse model names as fields, using a session
4
+ module WithSession
5
+ def self.included(parser_class)
6
+ parser_class.alias_method_chain :parse_field, :model
7
+ end
8
+
9
+ attr_accessor :session
10
+
11
+ def match_field
12
+ "(?:\\w+: (?:#{match_model}|\"#{match_quoted}\"))"
13
+ end
14
+
15
+ def parse_field_with_model(field)
16
+ if session && field =~ /^(\w+): #{capture_model}$/
17
+ {$1 => session.model($2)}
18
+ else
19
+ parse_field_without_model(field)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,19 +1,22 @@
1
1
  module Pickle
2
2
  class Session
3
- include Parser
4
-
3
+ def initialize(options = {})
4
+ self.parser = options[:parser] || Pickle.parser
5
+ @config = options[:config] || parser.config
6
+ end
7
+
5
8
  def create_model(a_model_name, fields = nil)
6
- factory, name = *parse_model(a_model_name)
7
- raise ArgumentError, "Can't create a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
8
- record = Factory(factory, parse_fields(fields))
9
- store_model(factory, name, record)
9
+ factory, label = *parser.parse_model(a_model_name)
10
+ raise ArgumentError, "Can't create with an ordinal (e.g. 1st user)" if label.is_a?(Integer)
11
+ record = config.factories[factory].create(parser.parse_fields(fields))
12
+ store_model(factory, label, record)
10
13
  end
11
14
 
12
15
  def find_model(a_model_name, fields)
13
- model, name = *parse_model(a_model_name)
16
+ model, name = *parser.parse_model(a_model_name)
14
17
  raise ArgumentError, "Can't find a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
15
18
  model_class = model.classify.constantize
16
- if record = model_class.find(:first, :conditions => convert_models_to_attributes(model_class, parse_fields(fields)))
19
+ if record = model_class.find(:first, :conditions => convert_models_to_attributes(model_class, parser.parse_fields(fields)))
17
20
  store_model(model, name, record)
18
21
  else
19
22
  raise ActiveRecord::RecordNotFound, "Couldn't find #{model} with #{fields}"
@@ -21,8 +24,8 @@ module Pickle
21
24
  end
22
25
 
23
26
  # return the original model stored by create_model or find_model
24
- def original_model(a_model_name)
25
- factory, name_or_index = *parse_model(a_model_name)
27
+ def created_model(a_model_name)
28
+ factory, name_or_index = *parser.parse_model(a_model_name)
26
29
 
27
30
  if name_or_index.blank?
28
31
  models_by_factory(factory).last
@@ -34,13 +37,13 @@ module Pickle
34
37
  end
35
38
 
36
39
  # predicate version which raises no errors
37
- def original_model?(a_model_name)
38
- (original_model(a_model_name) rescue nil) ? true : false
40
+ def created_model?(a_model_name)
41
+ (created_model(a_model_name) rescue nil) ? true : false
39
42
  end
40
43
 
41
44
  # return a newly selected model
42
45
  def model(a_model_name)
43
- if model = original_model(a_model_name)
46
+ if model = created_model(a_model_name)
44
47
  model.class.find(model.id) or raise ActiveRecord::RecordNotFound, "model: #{a_model_name} could not be found in the database"
45
48
  end
46
49
  end
@@ -51,27 +54,25 @@ module Pickle
51
54
  end
52
55
 
53
56
  # return all original models of specified type
54
- def original_models(factory)
57
+ def created_models(factory)
55
58
  models_by_factory(factory)
56
59
  end
57
60
 
58
61
  # return all models of specified type (freshly selected from the database)
59
62
  def models(factory)
60
- original_models(factory).map do |model|
63
+ created_models(factory).map do |model|
61
64
  model.class.find(model.id)
62
65
  end
63
66
  end
64
67
 
65
- def parse_field_with_model(field)
66
- if field =~ /^(\w+): (#{Match::Model})$/
67
- {$1 => model($2)}
68
- else
69
- parse_field_without_model(field)
70
- end
68
+ protected
69
+ attr_reader :parser, :config
70
+
71
+ def parser=(parser)
72
+ parser.session = self
73
+ @parser = parser
71
74
  end
72
- alias_method_chain :parse_field, :model
73
-
74
- private
75
+
75
76
  def convert_models_to_attributes(ar_class, attrs)
76
77
  attrs.each do |key, val|
77
78
  if val.is_a?(ActiveRecord::Base) && ar_class.column_names.include?("#{key}_id")
@@ -94,7 +95,7 @@ module Pickle
94
95
 
95
96
  # if the factory name != the model name, store under both names
96
97
  def store_model(factory, name, record)
97
- store_record(canonical(record.class.name), name, record) if canonical(record.class.name) != factory
98
+ store_record(parser.canonical(record.class.name), name, record) if parser.canonical(record.class.name) != factory
98
99
  store_record(factory, name, record)
99
100
  end
100
101
 
@@ -0,0 +1,9 @@
1
+ module Pickle
2
+ module Version
3
+ Major = 0
4
+ Minor = 1
5
+ Tiny = 2
6
+
7
+ String = [Major, Minor, Tiny].join('.')
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ class PickleGenerator < Rails::Generator::Base
2
+ def initialize(*args)
3
+ super(*args)
4
+ File.exists?('features/support/env.rb') or raise "features/support/env.rb not found, try running script/generate cucumber"
5
+ end
6
+
7
+ def manifest
8
+ record do |m|
9
+ m.directory File.join('features/step_definitions')
10
+ m.template 'pickle_steps.rb', File.join('features/step_definitions', "pickle_steps.rb")
11
+ current_env = File.read('features/support/env.rb')
12
+ if current_env.include?("require 'pickle'")
13
+ logger.skipped "features/support/env.rb, as it already requires pickle"
14
+ else
15
+ m.template 'env.rb', File.join('features/support', "env.rb"), :assigns => {:current_env => current_env}, :collision => :force
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ <%= current_env %>
2
+ # to configure pickle, uncomment the following lines
3
+ # require 'pickle/config'
4
+ # Pickle.config do |pickle|
5
+ # pickle.adaptors = [:machinist]
6
+ # pickle.map 'I', 'myself', 'me', 'my', :to => 'user: "me"'
7
+ # end
8
+
9
+ require 'pickle'
@@ -0,0 +1,23 @@
1
+ # this file generated by script/generate pickle
2
+
3
+ Given(/^#{CaptureModel} exists$/) do |name|
4
+ create_model(name)
5
+ end
6
+
7
+ Given(/^#{CaptureModel} exists with #{CaptureFields}$/) do |name, fields|
8
+ create_model(name, fields)
9
+ end
10
+
11
+ Then(/^#{CaptureModel} should exist with #{CaptureFields}$/) do |name, fields|
12
+ find_model(name, fields).should be_present
13
+ end
14
+
15
+ Then(/^#{CaptureModel} should (?:be|have) (?:an? )?([\w ]+)$/) do |name, predicate|
16
+ predicate_method = predicate.gsub(' ', '_')
17
+ model(name).should send("be_#{predicate_method}")
18
+ end
19
+
20
+ Then(/^#{CaptureModel} should not (?:be|have) (?:an? )?([\w ]+)$/) do |name, predicate|
21
+ predicate_method = predicate.gsub(' ', '_')
22
+ model(name).should_not send("be_#{predicate_method}")
23
+ end
@@ -0,0 +1,128 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Pickle::Adapter do
4
+ it ".factories should raise NotImplementedError" do
5
+ lambda{ Pickle::Adapter.factories }.should raise_error(NotImplementedError)
6
+ end
7
+
8
+ it "#create should raise NotImplementedError" do
9
+ lambda{ Pickle::Adapter.new.create }.should raise_error(NotImplementedError)
10
+ end
11
+
12
+ it ".model_classes should not include CGI::Session::ActiveRecordStore" do
13
+ Pickle::Adapter.model_classes.should_not include(CGI::Session::ActiveRecordStore)
14
+ end
15
+
16
+ describe '::ActiveRecord' do
17
+ before do
18
+ # set up a fake object space
19
+ @klass1 = mock('One', :name => 'One')
20
+ @klass2 = mock('One::Two', :name => 'One::Two')
21
+ Pickle::Adapter::ActiveRecord.stub!(:model_classes).and_return([@klass1, @klass2])
22
+ end
23
+
24
+ describe ".factories" do
25
+ it "should create one for each active record class" do
26
+ Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass1).once
27
+ Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass2).once
28
+ Pickle::Adapter::ActiveRecord.factories
29
+ end
30
+
31
+ describe ".new(Class)" do
32
+ before do
33
+ @factory = Pickle::Adapter::ActiveRecord.new(@klass2)
34
+ end
35
+
36
+ it "should have underscored (s/_) name of Class as #name" do
37
+ @factory.name.should == 'one_two'
38
+ end
39
+
40
+ it "#create(attrs) should call Class.create!(attrs)" do
41
+ @klass2.should_receive(:create!).with({:key => "val"})
42
+ @factory.create(:key => "val")
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '::FactoryGirl' do
49
+ before do
50
+ # set up a fake object space
51
+ Factory.stub!(:factories).and_return(:one => nil, :two => nil)
52
+ end
53
+
54
+ describe ".factories" do
55
+ it "should create one for each factory" do
56
+ Pickle::Adapter::FactoryGirl.should_receive(:new).with(:one).once
57
+ Pickle::Adapter::FactoryGirl.should_receive(:new).with(:two).once
58
+ Pickle::Adapter::FactoryGirl.factories
59
+ end
60
+
61
+ describe ".new(:factory_name)" do
62
+ before do
63
+ @factory = Pickle::Adapter::FactoryGirl.new(:one)
64
+ end
65
+
66
+ it "should have name of factory key" do
67
+ @factory.name.should == 'one'
68
+ end
69
+
70
+ it "#create(attrs) should call Factory(<:key>, attrs)" do
71
+ Factory.should_receive(:create).with("one", {:key => "val"})
72
+ @factory.create(:key => "val")
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '::Machinist' do
79
+ before do
80
+ # set up a fake object space
81
+ @klass1 = mock('One', :name => 'One', :make => true, :make_unsaved => true)
82
+ @klass1.instance_variable_set('@blueprint', true)
83
+ @klass2 = mock('Two', :name => 'Two')
84
+ @klass3 = mock('Two::Sub', :name => 'Two::Sub', :make_special => true, :make => true, :make_unsaved => true)
85
+ @klass3.instance_variable_set('@blueprint', true)
86
+ Pickle::Adapter::Machinist.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])
87
+ end
88
+
89
+ describe ".factories" do
90
+ it "should create one for each machinist make method, except make_unsaved" do
91
+ Pickle::Adapter::Machinist.should_receive(:new).with(@klass1, 'make').once
92
+ Pickle::Adapter::Machinist.should_receive(:new).with(@klass3, 'make').once
93
+ Pickle::Adapter::Machinist.should_receive(:new).with(@klass3, 'make_special').once
94
+ Pickle::Adapter::Machinist.factories
95
+ end
96
+
97
+ describe ".new(Class, 'make')" do
98
+ before do
99
+ @factory = Pickle::Adapter::Machinist.new(@klass1, 'make')
100
+ end
101
+
102
+ it "should have underscored (s/_) name of Class as #name" do
103
+ @factory.name.should == 'one'
104
+ end
105
+
106
+ it "#create(attrs) should call Class.make(attrs)" do
107
+ @klass1.should_receive(:make).with({:key => "val"})
108
+ @factory.create(:key => "val")
109
+ end
110
+ end
111
+
112
+ describe ".new(Class, 'make_special')" do
113
+ before do
114
+ @factory = Pickle::Adapter::Machinist.new(@klass3, 'make_special')
115
+ end
116
+
117
+ it "should have 'special_<Class name>' as #name" do
118
+ @factory.name.should == 'special_two_sub'
119
+ end
120
+
121
+ it "#create(attrs) should call Class.make_special(attrs)" do
122
+ @klass3.should_receive(:make_special).with({:key => "val"})
123
+ @factory.create(:key => "val")
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -1,46 +1,100 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+ require 'pickle/config'
2
3
 
3
4
  describe Pickle::Config do
4
5
  before do
5
- # zero pickle config before each example
6
- [:names, :model_names, :factory_names, :mappings].each do |config_var|
7
- instance_variable_set "@orig_#{config_var}", Pickle::Config.send(config_var)
8
- Pickle::Config.send("#{config_var}=", nil)
6
+ @config = Pickle::Config.new
7
+ end
8
+
9
+ it "#adapters should default to :machinist, :factory_girl, :active_record" do
10
+ @config.adapters.should == [:machinist, :factory_girl, :active_record]
11
+ end
12
+
13
+ it "#adapter_classes should default to Adapter::Machinist, Adapter::FactoryGirl, Adapter::ActiveRecord" do
14
+ @config.adapter_classes.should == [Pickle::Adapter::Machinist, Pickle::Adapter::FactoryGirl, Pickle::Adapter::ActiveRecord]
15
+ end
16
+
17
+ describe "setting adapters to [:machinist, SomeAdapter]" do
18
+ class SomeAdapter; end
19
+
20
+ before do
21
+ @config.adapters = [:machinist, SomeAdapter]
22
+ end
23
+
24
+ it "#adapter_classes should be Adapter::Machinist, SomeAdapter" do
25
+ @config.adapter_classes.should == [Pickle::Adapter::Machinist, SomeAdapter]
9
26
  end
10
27
  end
11
28
 
12
- after do
13
- # restore pickle config back after each example
14
- [:model_names, :factory_names, :names, :mappings].each do |config_var|
15
- Pickle::Config.send "#{config_var}=", instance_variable_get("@orig_#{config_var}")
29
+ describe "#factories" do
30
+ it "should call adaptor.factories for each adaptor" do
31
+ Pickle::Adapter::Machinist.should_receive(:factories).and_return([])
32
+ Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([])
33
+ Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([])
34
+ @config.factories
35
+ end
36
+
37
+ it "should aggregate factories into a hash using factory name as key" do
38
+ Pickle::Adapter::Machinist.should_receive(:factories).and_return([@machinist = mock('machinist', :name => 'machinist')])
39
+ Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([@factory_girl = mock('factory_girl', :name => 'factory_girl')])
40
+ Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([@active_record = mock('active_record', :name => 'active_record')])
41
+ @config.factories.should == {'machinist' => @machinist, 'factory_girl' => @factory_girl, 'active_record' => @active_record}
16
42
  end
43
+
44
+ it "should give preference to adaptors first in the list" do
45
+ Pickle::Adapter::Machinist.should_receive(:factories).and_return([@machinist_one = mock('one', :name => 'one')])
46
+ Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([@factory_girl_one = mock('one', :name => 'one'), @factory_girl_two = mock('two', :name => 'two')])
47
+ Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([@active_record_two = mock('two', :name => 'two'), @active_record_three = mock('three', :name => 'three')])
48
+ @config.factories.should == {'one' => @machinist_one, 'two' => @factory_girl_two, 'three' => @active_record_three}
49
+ end
50
+ end
51
+
52
+ it "#factory_names should be keys of #factories" do
53
+ @config.should_receive(:factories).and_return('one' => nil, 'two' => nil)
54
+ @config.factory_names.sort.should == ['one', 'two'].sort
17
55
  end
18
56
 
19
- it ":factory_names should default to stringified keys of Factory.factories" do
20
- Factory.factories.should_receive(:keys).and_return([:one, :two])
21
- Pickle::Config.factory_names.should == ['one', 'two']
57
+ it "#mappings should default to []" do
58
+ @config.mappings.should == []
59
+ end
60
+
61
+ describe "#map 'foo', :to => 'faz'" do
62
+ before do
63
+ @config.map 'foo', :to => 'faz'
64
+ end
65
+
66
+ it "should create OpenStruct(search: 'foo', replace: 'faz') mapping" do
67
+ @config.mappings.first.should == OpenStruct.new(:search => 'foo', :replace => 'faz')
68
+ end
22
69
  end
23
70
 
24
- it ":model_names should default to directory listing of app/models excluding observers" do
25
- models_path = "#{RAILS_ROOT}/app/models"
26
- Dir.should_receive(:[]).with("#{models_path}/**/*.rb").and_return([
27
- "#{models_path}/one.rb",
28
- "#{models_path}/one/a.rb",
29
- "#{models_path}/one/b.rb",
30
- "#{models_path}/one/b/i.rb",
31
- "#{models_path}/one_observer.rb",
32
- "#{models_path}/two.rb"
33
- ])
34
- Pickle::Config.model_names.should == ['one', 'one/a', 'one/b', 'one/b/i', 'two']
71
+ describe "#map 'foo', 'bar' :to => 'faz'" do
72
+ before do
73
+ @config.map 'foo', 'bar', :to => 'faz'
74
+ end
75
+
76
+ it "should create OpenStruct(search: '(?:foo|bar)', replace: 'faz') mapping" do
77
+ @config.mappings.first.should == OpenStruct.new(:search => '(?:foo|bar)', :replace => 'faz')
78
+ end
35
79
  end
36
80
 
37
- it ":names should default to set (Array) :factory and :model names" do
38
- Pickle::Config.factory_names = ['one', 'two']
39
- Pickle::Config.model_names = ['two', 'one/a', 'one/b']
40
- Pickle::Config.names.sort.should == ['one', 'one/a', 'one/b', 'two']
81
+ it "#configure(&block) should execiute on self" do
82
+ @config.should_receive(:foo).with(:bar)
83
+ @config.configure do |c|
84
+ c.foo :bar
85
+ end
41
86
  end
42
87
 
43
- it ":mappings should default to []" do
44
- Pickle::Config.mappings.should == []
88
+ describe "Pickle.config" do
89
+ it "should refer to same object" do
90
+ Pickle.config.should == Pickle.config
91
+ end
92
+
93
+ it "called with (&block) should execute on the config" do
94
+ Pickle.config.should_receive(:foo).with(:bar)
95
+ Pickle.config do |c|
96
+ c.foo :bar
97
+ end
98
+ end
45
99
  end
46
100
  end