ianwhite-pickle 0.1.1
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/History.txt +11 -0
- data/License.txt +20 -0
- data/README.textile +67 -0
- data/Todo.txt +5 -0
- data/lib/pickle/injector.rb +18 -0
- data/lib/pickle/parser.rb +82 -0
- data/lib/pickle/session.rb +106 -0
- data/lib/pickle/steps.rb +27 -0
- data/lib/pickle.rb +47 -0
- data/spec/lib/pickle_config_spec.rb +46 -0
- data/spec/lib/pickle_injector_spec.rb +22 -0
- data/spec/lib/pickle_parser_spec.rb +164 -0
- data/spec/lib/pickle_session_spec.rb +281 -0
- metadata +70 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Ian White - ian.w.white@ardes.com
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
h1. Pickle [Experimental: In development]
|
2
|
+
|
3
|
+
Stick this in vendor/plugins to have cucumber steps that create your models easily from factory_girl/machinist
|
4
|
+
|
5
|
+
References to the models are stored, not for the purpose of checking the db (although you could use it for
|
6
|
+
that), but for enabling easy reference to urls, and for building complex givens which require a bunch of
|
7
|
+
models collaborating
|
8
|
+
|
9
|
+
h2. Example
|
10
|
+
|
11
|
+
If you have a user model, which has admin? and moderator? predicate methods
|
12
|
+
and let's say you have an :admin, :user, and :moderator factory, you can do this in a Scenario:
|
13
|
+
|
14
|
+
And an admin exists
|
15
|
+
And a moderator exists
|
16
|
+
|
17
|
+
# the following is just to show how refs work, obviously you'd not want to test this
|
18
|
+
Then the moderator should be a moderator
|
19
|
+
And the admin should be an admin
|
20
|
+
And the moderator should not be an admin
|
21
|
+
|
22
|
+
h2. Usage
|
23
|
+
|
24
|
+
script/generate pickle
|
25
|
+
|
26
|
+
h2. API
|
27
|
+
|
28
|
+
h3. Regexps for us in your own steps
|
29
|
+
|
30
|
+
If you want to use pickle expressions in your own steps, make sure you
|
31
|
+
require pickle in that file
|
32
|
+
|
33
|
+
require 'pickle'
|
34
|
+
|
35
|
+
For matching english versions of model names you get
|
36
|
+
|
37
|
+
#match_model, #capture_model
|
38
|
+
|
39
|
+
Given /^#{capture_model} exists$/ do |model_name|
|
40
|
+
model(model_name).should_not == nil
|
41
|
+
end
|
42
|
+
|
43
|
+
Then /^I should be at the (.*?) page$/ |page|
|
44
|
+
if page =~ /#{match_model}'s/
|
45
|
+
url_for(model(page.sub("'s",''))
|
46
|
+
else
|
47
|
+
# ...
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
For matching a field string, you get
|
52
|
+
|
53
|
+
#match_fields, #capture_fields
|
54
|
+
|
55
|
+
Given /^#{capture_model} exists with #{capture_fields}$/ do |model_name, fields|
|
56
|
+
create_model(model_name, fields)
|
57
|
+
end
|
58
|
+
|
59
|
+
Take a look at features/step_definitions/pickle_steps.rb for more examples
|
60
|
+
|
61
|
+
h3. Creating and tracking models
|
62
|
+
|
63
|
+
#create_model(<model_name>[, <field string>])
|
64
|
+
|
65
|
+
#find_model(<model_name>[, <field string>])
|
66
|
+
|
67
|
+
#model(<model_model>) # refers to a model that has already been created/found (ie. referred to in a scenario)
|
data/Todo.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pickle
|
2
|
+
module Injector
|
3
|
+
def self.inject(session, options = {})
|
4
|
+
target = options[:into] || ActionController::Integration::Session
|
5
|
+
session_name = session.name.underscore.gsub('/','_')
|
6
|
+
|
7
|
+
target.class_eval <<-end_eval, __FILE__, __LINE__
|
8
|
+
def #{session_name}
|
9
|
+
@#{session_name} ||= #{session.name}.new
|
10
|
+
end
|
11
|
+
end_eval
|
12
|
+
|
13
|
+
delegate_methods = session.instance_methods - Object.instance_methods
|
14
|
+
delegate_methods << {:to => session_name}
|
15
|
+
target.delegate *delegate_methods
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Pickle
|
2
|
+
module Parser
|
3
|
+
module Match
|
4
|
+
Ordinal = '(?:\d+(?:st|nd|rd|th))'
|
5
|
+
Index = "(?:first|last|#{Ordinal})"
|
6
|
+
Prefix = '(?:1 |a |an |another |the |that )'
|
7
|
+
Quoted = '(?:[^\\"]|\\.)*'
|
8
|
+
Name = '(?::? "' + Quoted + '")'
|
9
|
+
|
10
|
+
# model matching - depends on Parse::Config, so load before this if non standard config requried
|
11
|
+
ModelMapping = "(?:#{Pickle::Config.mappings.map(&:first).map{|s| "(?:#{s})"}.join('|')})"
|
12
|
+
ModelName = "(?:#{Pickle::Config.names.map{|n| n.to_s.gsub('_','[_ ]').gsub('/','[:\/ ]')}.join('|')})"
|
13
|
+
IndexedModel = "(?:(?:#{Index} )?#{ModelName})"
|
14
|
+
NamedModel = "(?:#{ModelName}#{Name}?)"
|
15
|
+
Model = "(?:#{ModelMapping}|#{Prefix}?(?:#{IndexedModel}|#{NamedModel}))"
|
16
|
+
Field = '(?:\w+: (?:' + Model + '|"' + Quoted + '"))'
|
17
|
+
Fields = "(?:#{Field}, )*#{Field}"
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
# these are expressions which capture a sub expression
|
22
|
+
module Capture
|
23
|
+
Ordinal = '(?:(\d+)(?:st|nd|rd|th))'
|
24
|
+
Name = '(?::? "(' + Match::Quoted + ')")'
|
25
|
+
Field = '(?:(\w+): "(' + Match::Quoted + ')")'
|
26
|
+
end
|
27
|
+
|
28
|
+
# given a string like 'foo: "bar", bar: "baz"' returns {"foo" => "bar", "bar" => "baz"}
|
29
|
+
def parse_fields(fields)
|
30
|
+
if fields.blank?
|
31
|
+
{}
|
32
|
+
elsif fields =~ /^#{Match::Fields}$/
|
33
|
+
fields.scan(/(#{Match::Field})(?:,|$)/).inject({}) do |m, match|
|
34
|
+
m.merge(parse_field(match[0]))
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise ArgumentError, "The fields string is not in the correct format.\n\n'#{fields}' did not match: #{Match::Fields}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# given a string like 'foo: "bar"' returns {key => value}
|
42
|
+
def parse_field(field)
|
43
|
+
if field =~ /^#{Capture::Field}$/
|
44
|
+
{ $1 => $2 }
|
45
|
+
else
|
46
|
+
raise ArgumentError, "The field argument is not in the correct format.\n\n'#{field}' did not match: #{Match::Field}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# returns really underscored name
|
51
|
+
def canonical(str)
|
52
|
+
str.to_s.gsub(' ','_').underscore
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_index(index)
|
56
|
+
case index
|
57
|
+
when '', /last/ then -1
|
58
|
+
when /#{Capture::Ordinal}/ then $1.to_i - 1
|
59
|
+
when /first/ then 0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
# return [factory, name or integer index]
|
65
|
+
def parse_model(name)
|
66
|
+
apply_mappings!(name)
|
67
|
+
if /(#{Match::ModelName})#{Capture::Name}$/ =~ name
|
68
|
+
[canonical($1), canonical($2)]
|
69
|
+
elsif /(#{Match::Index}) (#{Match::ModelName})$/ =~ name
|
70
|
+
[canonical($2), parse_index($1)]
|
71
|
+
else
|
72
|
+
/(#{Match::ModelName})#{Capture::Name}?$/ =~ name && [canonical($1), canonical($2)]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def apply_mappings!(string)
|
77
|
+
Pickle::Config.mappings.each do |(search, replace)|
|
78
|
+
string.sub! /^(?:#{search})$/, replace
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Pickle
|
2
|
+
class Session
|
3
|
+
include Parser
|
4
|
+
|
5
|
+
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)
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_model(a_model_name, fields)
|
13
|
+
model, name = *parse_model(a_model_name)
|
14
|
+
raise ArgumentError, "Can't find a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
|
15
|
+
model_class = model.classify.constantize
|
16
|
+
if record = model_class.find(:first, :conditions => convert_models_to_attributes(model_class, parse_fields(fields)))
|
17
|
+
store_model(model, name, record)
|
18
|
+
else
|
19
|
+
raise ActiveRecord::RecordNotFound, "Couldn't find #{model} with #{fields}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# 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)
|
26
|
+
|
27
|
+
if name_or_index.blank?
|
28
|
+
models_by_factory(factory).last
|
29
|
+
elsif name_or_index.is_a?(Integer)
|
30
|
+
models_by_factory(factory)[name_or_index]
|
31
|
+
else
|
32
|
+
models_by_name(factory)[name_or_index] or raise "model: #{a_model_name} does not refer to known model in this scenario"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# predicate version which raises no errors
|
37
|
+
def original_model?(a_model_name)
|
38
|
+
(original_model(a_model_name) rescue nil) ? true : false
|
39
|
+
end
|
40
|
+
|
41
|
+
# return a newly selected model
|
42
|
+
def model(a_model_name)
|
43
|
+
if model = original_model(a_model_name)
|
44
|
+
model.class.find(model.id) or raise ActiveRecord::RecordNotFound, "model: #{a_model_name} could not be found in the database"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# predicate version which raises no errors
|
49
|
+
def model?(a_model_name)
|
50
|
+
(model(a_model_name) rescue nil) ? true : false
|
51
|
+
end
|
52
|
+
|
53
|
+
# return all original models of specified type
|
54
|
+
def original_models(factory)
|
55
|
+
models_by_factory(factory)
|
56
|
+
end
|
57
|
+
|
58
|
+
# return all models of specified type (freshly selected from the database)
|
59
|
+
def models(factory)
|
60
|
+
original_models(factory).map do |model|
|
61
|
+
model.class.find(model.id)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
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
|
71
|
+
end
|
72
|
+
alias_method_chain :parse_field, :model
|
73
|
+
|
74
|
+
private
|
75
|
+
def convert_models_to_attributes(ar_class, attrs)
|
76
|
+
attrs.each do |key, val|
|
77
|
+
if val.is_a?(ActiveRecord::Base) && ar_class.column_names.include?("#{key}_id")
|
78
|
+
attrs["#{key}_id"] = val.id
|
79
|
+
attrs["#{key}_type"] = val.class.name if ar_class.column_names.include?("#{key}_type")
|
80
|
+
attrs.delete(key)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def models_by_name(factory)
|
86
|
+
@models_by_name ||= {}
|
87
|
+
@models_by_name[factory] ||= {}
|
88
|
+
end
|
89
|
+
|
90
|
+
def models_by_factory(factory)
|
91
|
+
@models_by_factory ||= {}
|
92
|
+
@models_by_factory[factory] ||= []
|
93
|
+
end
|
94
|
+
|
95
|
+
# if the factory name != the model name, store under both names
|
96
|
+
def store_model(factory, name, record)
|
97
|
+
store_record(canonical(record.class.name), name, record) if canonical(record.class.name) != factory
|
98
|
+
store_record(factory, name, record)
|
99
|
+
end
|
100
|
+
|
101
|
+
def store_record(factory, name, record)
|
102
|
+
models_by_name(factory)[name] = record
|
103
|
+
models_by_factory(factory) << record
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/pickle/steps.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# inject the pickle session into integration session
|
2
|
+
Pickle::Injector.inject Pickle::Session, :into => ActionController::Integration::Session
|
3
|
+
|
4
|
+
# make some Regexp shortcuts for use in steps
|
5
|
+
MatchModel = Pickle::Parser::Match::Model
|
6
|
+
MatchFields = Pickle::Parser::Match::Fields
|
7
|
+
|
8
|
+
# start with some obvious steps
|
9
|
+
Given(/^(#{MatchModel}) exists$/) do |name|
|
10
|
+
create_model(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
Given(/^(#{MatchModel}) exists with (#{MatchFields})$/) do |name, fields|
|
14
|
+
create_model(name, fields)
|
15
|
+
end
|
16
|
+
|
17
|
+
Then(/^(#{MatchModel}) should exist with (#{MatchFields})$/) do |name, fields|
|
18
|
+
find_model(name, fields).should_not == nil
|
19
|
+
end
|
20
|
+
|
21
|
+
Then(/^(#{MatchModel}) should be (?:an? )?"(.*?)"$/) do |name, predicate|
|
22
|
+
model(name).should send("be_#{predicate.gsub(' ','_')}")
|
23
|
+
end
|
24
|
+
|
25
|
+
Then(/^(#{MatchModel}) should not be (?:an? )?"(.*?)"$/) do |name, predicate|
|
26
|
+
model(name).should_not send("be_#{predicate.gsub(' ','_')}")
|
27
|
+
end
|
data/lib/pickle.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Pickle == cucumber + factory
|
2
|
+
#
|
3
|
+
# = Usage
|
4
|
+
# # in features/steps/_env.rb
|
5
|
+
# require 'pickle/steps'
|
6
|
+
#
|
7
|
+
# If you need to configure pickle, do it like this
|
8
|
+
#
|
9
|
+
# Pickle::Config.map 'I|me|my', :to => 'user: "me"'
|
10
|
+
# require 'pickle/steps'
|
11
|
+
module Pickle
|
12
|
+
module Version
|
13
|
+
Major = 0
|
14
|
+
Minor = 1
|
15
|
+
Tiny = 1
|
16
|
+
|
17
|
+
String = [Major, Minor, Tiny].join('.')
|
18
|
+
end
|
19
|
+
|
20
|
+
module Config
|
21
|
+
class << self
|
22
|
+
attr_writer :model_names, :factory_names, :names, :mappings
|
23
|
+
|
24
|
+
def model_names
|
25
|
+
@model_names ||= Dir["#{RAILS_ROOT}/app/models/**/*.rb"].reject{|f| f =~ /observer.rb$/}.map{|f| f.sub("#{RAILS_ROOT}/app/models/",'').sub(".rb",'')}
|
26
|
+
end
|
27
|
+
|
28
|
+
def factory_names
|
29
|
+
require 'factory_girl'
|
30
|
+
@factory_names ||= Factory.factories.keys.map(&:to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def names
|
34
|
+
@names ||= (model_names | factory_names)
|
35
|
+
end
|
36
|
+
|
37
|
+
def mappings
|
38
|
+
@mappings ||= []
|
39
|
+
end
|
40
|
+
|
41
|
+
def map(search, options)
|
42
|
+
raise ArgumentError, "Usage: map 'search', :to => 'replace'" unless search.is_a?(String) && options[:to].is_a?(String)
|
43
|
+
self.mappings << [search, options[:to]]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Pickle::Config do
|
4
|
+
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)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
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}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
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']
|
22
|
+
end
|
23
|
+
|
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']
|
35
|
+
end
|
36
|
+
|
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']
|
41
|
+
end
|
42
|
+
|
43
|
+
it ":mappings should default to []" do
|
44
|
+
Pickle::Config.mappings.should == []
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Pickle::Injector do
|
4
|
+
describe ".inject Pickle::Session, :into => <a class>" do
|
5
|
+
before do
|
6
|
+
@class = Class.new
|
7
|
+
Pickle::Injector.inject Pickle::Session, :into => @class
|
8
|
+
@object = @class.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "object should respond_to Pickle:Session methods" do
|
12
|
+
@object.should respond_to(:model)
|
13
|
+
@object.should respond_to(:create_model)
|
14
|
+
@object.should respond_to(:find_model)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "object.model (a pickle method) should call object.pickle_session.model" do
|
18
|
+
@object.pickle_session.should_receive(:model).with('a user')
|
19
|
+
@object.model('a user')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Pickle::Parser do
|
4
|
+
include Pickle::Parser
|
5
|
+
|
6
|
+
describe "Match atoms" do
|
7
|
+
def self.atom_should_match(atom, strings)
|
8
|
+
Array(strings).each do |string|
|
9
|
+
it "#{atom} should match '#{string}'" do
|
10
|
+
string.should match(/^#{eval "Pickle::Parser::#{atom}"}$/)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.atom_should_not_match(atom, strings)
|
16
|
+
Array(strings).each do |string|
|
17
|
+
it "#{atom} should NOT match '#{string}'" do
|
18
|
+
string.should_not match(/^#{eval "Pickle::Parser::#{atom}"}$/)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
atom_should_match 'Match::Ordinal', ['1st', '2nd', '23rd', '104th']
|
24
|
+
atom_should_not_match 'Match::Ordinal', ['1', '2']
|
25
|
+
|
26
|
+
atom_should_match 'Match::Index', ['first', 'last', '23rd', '104th']
|
27
|
+
atom_should_not_match 'Match::Index', ['1', '2', 'foo']
|
28
|
+
|
29
|
+
atom_should_match 'Match::Name', [': "gday"', ': "gday mate"']
|
30
|
+
atom_should_not_match 'Match::Name', [': "gday""', ': gday']
|
31
|
+
|
32
|
+
atom_should_match 'Match::Field', ['foo: "this is the life"', 'bar_man: "and so is this"']
|
33
|
+
atom_should_not_match 'Match::Field', ['foo bar: "this aint workin"']
|
34
|
+
|
35
|
+
atom_should_match 'Match::Fields', ['foo: "bar"', 'foo: "bar", baz: "bah"']
|
36
|
+
atom_should_not_match 'Match::Fields', ['foo bar: "baz"', 'email: "a", password: "b", and password_confirmation: "c"']
|
37
|
+
|
38
|
+
atom_should_match 'Match::Model', ['a user', '1st fast car', 'the 23rd fast_car', 'an event:create', 'the 2nd event/create', 'that event create: "zing"']
|
39
|
+
atom_should_not_match 'Match::Model', ['a giraffe', 'a 1st faster car: "jim"', 'an event created']
|
40
|
+
|
41
|
+
atom_should_match 'Match::ModelName', ['user', 'fast car', 'fast_car', 'event:create', 'event/create', 'event create']
|
42
|
+
atom_should_not_match 'Match::ModelName', ['users', 'faster car', 'event created']
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'misc regexps' do
|
46
|
+
describe '/^(#{Pickle::Parser::Match::Model}) exists/' do
|
47
|
+
before do
|
48
|
+
@regexp = /^(#{Pickle::Parser::Match::Model}) exists$/
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should match 'a user exists'" do
|
52
|
+
'a user exists'.should match(@regexp)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should caputure 'a user' from 'a user exists'" do
|
56
|
+
'a user exists'.match(@regexp)[1].should == 'a user'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#parse_field' do
|
62
|
+
it "should return {'a' => 'b'} for 'a: \"b\"'" do
|
63
|
+
parse_field('a: "b"').should == {'a' => 'b'}
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should raise error for invalid field 'a : b'" do
|
67
|
+
lambda { parse_field('a : b') }.should raise_error(ArgumentError)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#parse_fields' do
|
72
|
+
it 'should return {} for blank argument' do
|
73
|
+
parse_fields(nil).should == {}
|
74
|
+
parse_fields('').should == {}
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should raise error for invalid argument' do
|
78
|
+
lambda { parse_fields('foo foo') }.should raise_error(ArgumentError)
|
79
|
+
end
|
80
|
+
|
81
|
+
it '(\'foo: "bar"\') should == { "foo" => "bar"}' do
|
82
|
+
parse_fields('foo: "bar"').should == { "foo" => "bar"}
|
83
|
+
end
|
84
|
+
|
85
|
+
it '(\'foo: "bar", bar_man: "wonga wonga", gump: "123"\') should == {"foo" => "bar", "bar_man" => "wonga wonga", "gump" => "123"}' do
|
86
|
+
parse_fields('foo: "bar", bar_man: "wonga wonga", gump: "123"').should == {"foo" => "bar", "bar_man" => "wonga wonga", "gump" => "123"}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#parse_model' do
|
91
|
+
it '("a user") should == ["user", ""]' do
|
92
|
+
parse_model("a user").should == ["user", ""]
|
93
|
+
end
|
94
|
+
|
95
|
+
it '("the user") should == ["user", ""]' do
|
96
|
+
parse_model("the user").should == ["user", ""]
|
97
|
+
end
|
98
|
+
|
99
|
+
it '("1 fast car") should == ["fast_car", ""]' do
|
100
|
+
parse_model("1 fast car").should == ["fast_car", ""]
|
101
|
+
end
|
102
|
+
|
103
|
+
it '(\'an user: "jim jones"\') should == ["user", "jim_jones"]' do
|
104
|
+
parse_model('an user: "jim jones"').should == ["user", "jim_jones"]
|
105
|
+
end
|
106
|
+
|
107
|
+
it '(\'that fast car: "herbie"\') should == ["fast_car", "herbie"]' do
|
108
|
+
parse_model('that fast car: "herbie"').should == ["fast_car", "herbie"]
|
109
|
+
end
|
110
|
+
|
111
|
+
it '(\'the 12th user\') should == ["user", 11]' do
|
112
|
+
parse_model('the 12th user').should == ["user", 11]
|
113
|
+
end
|
114
|
+
|
115
|
+
it '(\'the last user\') should == ["user", -1]' do
|
116
|
+
parse_model('the last user').should == ["user", -1]
|
117
|
+
end
|
118
|
+
|
119
|
+
it '("the first user") should == ["user", 0]' do
|
120
|
+
parse_model('the first user').should == ["user", 0]
|
121
|
+
end
|
122
|
+
|
123
|
+
it '("the 1st user") should == ["user", 0]' do
|
124
|
+
parse_model('the 1st user').should == ["user", 0]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#parse_index" do
|
129
|
+
it '("1st") should == 0' do
|
130
|
+
parse_index("1st").should == 0
|
131
|
+
end
|
132
|
+
|
133
|
+
it '("24th") should == 23' do
|
134
|
+
parse_index("24th").should == 23
|
135
|
+
end
|
136
|
+
it '("first") should == 0' do
|
137
|
+
parse_index("first").should == 0
|
138
|
+
end
|
139
|
+
|
140
|
+
it '("last") should == -1' do
|
141
|
+
parse_index("last").should == -1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "customised mappings" do
|
146
|
+
describe 'Pickle::Config.map "I|myself", :to => \'user: "me"\'' do
|
147
|
+
it "'I' should match /\#{Pickle::Parser::Match::Model}/" do
|
148
|
+
'I'.should match(/#{Pickle::Parser::Match::Model}/)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "'myself' should match /\#{Pickle::Parser::Match::Model}/" do
|
152
|
+
'myself'.should match(/#{Pickle::Parser::Match::Model}/)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "parse_the_model_name('I') should == ['user', 'me']" do
|
156
|
+
parse_model('I').should == ["user", "me"]
|
157
|
+
end
|
158
|
+
|
159
|
+
it "parse_the_model_name('myself') should == ['user', 'me']" do
|
160
|
+
parse_model('I').should == ["user", "me"]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Pickle::Session do
|
4
|
+
before do
|
5
|
+
@session = Pickle::Session.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "after storing a single user", :shared => true do
|
9
|
+
it "original_models('user') should be array containing the original user" do
|
10
|
+
@session.original_models('user').should == [@user]
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "the original user should be retrievable with" do
|
14
|
+
it "original_model('the user')" do
|
15
|
+
@session.original_model('the user').should == @user
|
16
|
+
end
|
17
|
+
|
18
|
+
it "original_model('1st user')" do
|
19
|
+
@session.original_model('1st user').should == @user
|
20
|
+
end
|
21
|
+
|
22
|
+
it "original_model('last user')" do
|
23
|
+
@session.original_model('last user').should == @user
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "(found from db)" do
|
28
|
+
before do
|
29
|
+
@user.stub!(:id).and_return(100)
|
30
|
+
@user.class.should_receive(:find).with(100).and_return(@user_from_db = @user.dup)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "models('user') should be array containing user" do
|
34
|
+
@session.models('user').should == [@user_from_db]
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "user should be retrievable with" do
|
38
|
+
it "model('the user')" do
|
39
|
+
@session.model('the user').should == @user_from_db
|
40
|
+
end
|
41
|
+
|
42
|
+
it "model('1st user')" do
|
43
|
+
@session.model('1st user').should == @user_from_db
|
44
|
+
end
|
45
|
+
|
46
|
+
it "model('last user')" do
|
47
|
+
@session.model('last user').should == @user_from_db
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#create_model" do
|
54
|
+
before do
|
55
|
+
@user = mock_model(User)
|
56
|
+
Factory.stub!(:create).and_return(@user)
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "('a user')" do
|
60
|
+
def do_create_model
|
61
|
+
@session.create_model('a user')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should call Factory.create('user', {})" do
|
65
|
+
Factory.should_receive(:create).with('user', {}).and_return(@user)
|
66
|
+
do_create_model
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "after create," do
|
70
|
+
before { do_create_model }
|
71
|
+
|
72
|
+
it_should_behave_like "after storing a single user"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "('1 user', 'foo: \"bar\", baz: \"bing bong\"')" do
|
77
|
+
def do_create_model
|
78
|
+
@session.create_model('1 user', 'foo: "bar", baz: "bing bong"')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should call Factory.create('user', {'foo' => 'bar', 'baz' => 'bing bong'})" do
|
82
|
+
Factory.should_receive(:create).with('user', {'foo' => 'bar', 'baz' => 'bing bong'}).and_return(@user)
|
83
|
+
do_create_model
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "after create," do
|
87
|
+
before { do_create_model }
|
88
|
+
|
89
|
+
it_should_behave_like "after storing a single user"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "('an user: \"fred\")" do
|
94
|
+
def do_create_model
|
95
|
+
@session.create_model('an user: "fred"')
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should call Factory.create('user', {})" do
|
99
|
+
Factory.should_receive(:create).with('user', {}).and_return(@user)
|
100
|
+
do_create_model
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "after create," do
|
104
|
+
before { do_create_model }
|
105
|
+
|
106
|
+
it_should_behave_like "after storing a single user"
|
107
|
+
|
108
|
+
it "original_model('the user: \"fred\"') should retrieve the user" do
|
109
|
+
@session.original_model('the user: "fred"').should == @user
|
110
|
+
end
|
111
|
+
|
112
|
+
it "original_model?('the user: \"shirl\"') should be false" do
|
113
|
+
@session.original_model?('the user: "shirl"').should == false
|
114
|
+
end
|
115
|
+
|
116
|
+
it "model?('the user: \"shirl\"') should be false" do
|
117
|
+
@session.model?('the user: "shirl"').should == false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#find_model' do
|
124
|
+
before do
|
125
|
+
@user = mock_model(User)
|
126
|
+
User.stub!(:find).and_return(@user)
|
127
|
+
end
|
128
|
+
|
129
|
+
def do_find_model
|
130
|
+
@session.find_model('a user', 'hair: "pink"')
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should call User.find :first, :conditions => {'hair' => 'pink'}" do
|
134
|
+
User.should_receive(:find).with(:first, :conditions => {'hair' => 'pink'}).and_return(@user)
|
135
|
+
do_find_model
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should raise RecordNotFound when no record returned" do
|
139
|
+
User.should_receive(:find).and_return(nil)
|
140
|
+
lambda { do_find_model }.should raise_error(ActiveRecord::RecordNotFound)
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "after find," do
|
144
|
+
before { do_find_model }
|
145
|
+
|
146
|
+
it_should_behave_like "after storing a single user"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe 'creating \'a super admin: "fred"\', then \'a user: "shirl"\', \'then 1 super_admin\'' do
|
151
|
+
before do
|
152
|
+
@user = @fred = mock_model(User)
|
153
|
+
@shirl = mock_model(User)
|
154
|
+
@noname = mock_model(User)
|
155
|
+
Factory.stub!(:create).and_return(@fred, @shirl, @noname)
|
156
|
+
end
|
157
|
+
|
158
|
+
def do_create_users
|
159
|
+
@session.create_model('a super admin: "fred"')
|
160
|
+
@session.create_model('a user: "shirl"')
|
161
|
+
@session.create_model('1 super_admin')
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should call Factory.create with <'super_admin'>, <'user'>, <'super_admin'>" do
|
165
|
+
Factory.should_receive(:create).with('super_admin', {}).twice
|
166
|
+
Factory.should_receive(:create).with('user', {}).once
|
167
|
+
do_create_users
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "after create," do
|
171
|
+
before do
|
172
|
+
do_create_users
|
173
|
+
end
|
174
|
+
|
175
|
+
it "original_models('user') should == [@fred, @shirl, @noname]" do
|
176
|
+
@session.original_models('user').should == [@fred, @shirl, @noname]
|
177
|
+
end
|
178
|
+
|
179
|
+
it "original_models('super_admin') should == [@fred, @noname]" do
|
180
|
+
@session.original_models('super_admin').should == [@fred, @noname]
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "#original_model" do
|
184
|
+
it "'that user' should be @noname (the last user created - as super_admins are users)" do
|
185
|
+
@session.original_model('that user').should == @noname
|
186
|
+
end
|
187
|
+
|
188
|
+
it "'the super admin' should be @noname (the last super admin created)" do
|
189
|
+
@session.original_model('that super admin').should == @noname
|
190
|
+
end
|
191
|
+
|
192
|
+
it "'the 1st super admin' should be @fred" do
|
193
|
+
@session.original_model('the 1st super admin').should == @fred
|
194
|
+
end
|
195
|
+
|
196
|
+
it "'the first user' should be @fred" do
|
197
|
+
@session.original_model('the first user').should == @fred
|
198
|
+
end
|
199
|
+
|
200
|
+
it "'the 2nd user' should be @shirl" do
|
201
|
+
@session.original_model('the 2nd user').should == @shirl
|
202
|
+
end
|
203
|
+
|
204
|
+
it "'the last user' should be @noname" do
|
205
|
+
@session.original_model('the last user').should == @noname
|
206
|
+
end
|
207
|
+
|
208
|
+
it "'the user: \"fred\" should be @fred" do
|
209
|
+
@session.original_model('the user: "fred"').should == @fred
|
210
|
+
end
|
211
|
+
|
212
|
+
it "'the user: \"shirl\" should be @shirl" do
|
213
|
+
@session.original_model('the user: "shirl"').should == @shirl
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "when 'the user: \"me\"' exists (and there is a mapping from 'I|myself' => 'user: \"me\")" do
|
220
|
+
before do
|
221
|
+
@user = mock_model(User)
|
222
|
+
User.stub!(:find).and_return(@user)
|
223
|
+
Factory.stub!(:create).and_return(@user)
|
224
|
+
@session.create_model('the user: "me"')
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'model("I") should return the user' do
|
228
|
+
@session.model('I').should == @user
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'model("myself") should return the user' do
|
232
|
+
@session.model('myself').should == @user
|
233
|
+
end
|
234
|
+
|
235
|
+
it "#parse_fields 'author: user \"JIM\"' should raise Error, as model deos not refer" do
|
236
|
+
lambda { @session.parse_fields('author: user "JIM"') }.should raise_error
|
237
|
+
end
|
238
|
+
|
239
|
+
it "#parse_fields 'author: the user' should return {\"author\" => <user>}" do
|
240
|
+
@session.parse_fields('author: the user').should == {"author" => @user}
|
241
|
+
end
|
242
|
+
|
243
|
+
it "#parse_fields 'author: myself' should return {\"author\" => <user>}" do
|
244
|
+
@session.parse_fields('author: myself').should == {"author" => @user}
|
245
|
+
end
|
246
|
+
|
247
|
+
it "#parse_fields 'author: the user, approver: I, rating: \"5\"' should return {'author' => <user>, 'approver' => <user>, 'rating' => '5'}" do
|
248
|
+
@session.parse_fields('author: the user, approver: I, rating: "5"').should == {'author' => @user, 'approver' => @user, 'rating' => '5'}
|
249
|
+
end
|
250
|
+
|
251
|
+
it "#parse_fields 'author: user: \"me\", approver: \"\"' should return {'author' => <user>, 'approver' => \"\"}" do
|
252
|
+
@session.parse_fields('author: user: "me", approver: ""').should == {'author' => @user, 'approver' => ""}
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "convert_models_to_attributes(ar_class, :user => <a user>)" do
|
257
|
+
before do
|
258
|
+
@user = mock_model(User)
|
259
|
+
end
|
260
|
+
|
261
|
+
describe "(when ar_class has column 'user_id')" do
|
262
|
+
before do
|
263
|
+
@ar_class = mock('ActiveRecord', :column_names => ['user_id'])
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should return {'user_id' => <the user.id>}" do
|
267
|
+
@session.send(:convert_models_to_attributes, @ar_class, :user => @user).should == {'user_id' => @user.id}
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "(when ar_class has columns 'user_id', 'user_type')" do
|
272
|
+
before do
|
273
|
+
@ar_class = mock('ActiveRecord', :column_names => ['user_id', 'user_type'])
|
274
|
+
end
|
275
|
+
|
276
|
+
it "should return {'user_id' => <the user.id>, 'user_type' => <the user.type>}" do
|
277
|
+
@session.send(:convert_models_to_attributes, @ar_class, :user => @user).should == {'user_id' => @user.id, 'user_type' => @user.class.name}
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ianwhite-pickle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ian White
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-12-27 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Easy model creation and reference in your cucumber features
|
17
|
+
email: ian.w.white@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/pickle/injector.rb
|
26
|
+
- lib/pickle/parser.rb
|
27
|
+
- lib/pickle/session.rb
|
28
|
+
- lib/pickle/steps.rb
|
29
|
+
- lib/pickle.rb
|
30
|
+
- License.txt
|
31
|
+
- README.textile
|
32
|
+
- Todo.txt
|
33
|
+
- History.txt
|
34
|
+
- spec/lib/pickle_config_spec.rb
|
35
|
+
- spec/lib/pickle_injector_spec.rb
|
36
|
+
- spec/lib/pickle_parser_spec.rb
|
37
|
+
- spec/lib/pickle_session_spec.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/ianwhite/pickle/tree
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --title
|
43
|
+
- Pickle
|
44
|
+
- --line-numbers
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Easy model creation and reference in your cucumber features
|
66
|
+
test_files:
|
67
|
+
- spec/lib/pickle_config_spec.rb
|
68
|
+
- spec/lib/pickle_injector_spec.rb
|
69
|
+
- spec/lib/pickle_parser_spec.rb
|
70
|
+
- spec/lib/pickle_session_spec.rb
|