ianwhite-pickle 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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