spbtv_pickle 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock.development +158 -0
  7. data/History.txt +499 -0
  8. data/License.txt +20 -0
  9. data/README.md +566 -0
  10. data/Rakefile +20 -0
  11. data/Rakefile.d/cucumber.rake +27 -0
  12. data/Rakefile.d/release.rake +44 -0
  13. data/Rakefile.d/rspec.rake +3 -0
  14. data/Rakefile.d/yard.rake +5 -0
  15. data/Todo.txt +3 -0
  16. data/autotest/discover.rb +9 -0
  17. data/features/app/app.rb +128 -0
  18. data/features/app/blueprints.rb +6 -0
  19. data/features/app/fabricators.rb +6 -0
  20. data/features/app/factories.rb +25 -0
  21. data/features/app/views/notifier/email.erb +1 -0
  22. data/features/app/views/notifier/user_email.erb +6 -0
  23. data/features/email/email.feature +64 -0
  24. data/features/generator/generators.feature +59 -0
  25. data/features/path/models_page.feature +44 -0
  26. data/features/path/named_route_page.feature +10 -0
  27. data/features/pickle/create_from_active_record.feature +83 -0
  28. data/features/pickle/create_from_fabrication.feature +46 -0
  29. data/features/pickle/create_from_factory_girl.feature +66 -0
  30. data/features/pickle/create_from_machinist.feature +46 -0
  31. data/features/step_definitions/email_steps.rb +1 -0
  32. data/features/step_definitions/extra_email_steps.rb +12 -0
  33. data/features/step_definitions/fork_steps.rb +4 -0
  34. data/features/step_definitions/generator_steps.rb +52 -0
  35. data/features/step_definitions/path_steps.rb +14 -0
  36. data/features/step_definitions/pickle_steps.rb +1 -0
  37. data/features/step_definitions/raise_error_steps.rb +7 -0
  38. data/features/support/email.rb +1 -0
  39. data/features/support/env.rb +14 -0
  40. data/features/support/paths.rb +47 -0
  41. data/features/support/pickle.rb +27 -0
  42. data/features/support/pickle_app.rb +4 -0
  43. data/init.rb +0 -0
  44. data/lib/generators/pickle_generator.rb +44 -0
  45. data/lib/pickle.rb +26 -0
  46. data/lib/pickle/adapter.rb +183 -0
  47. data/lib/pickle/adapters/active_record.rb +67 -0
  48. data/lib/pickle/adapters/data_mapper.rb +42 -0
  49. data/lib/pickle/adapters/mongoid.rb +54 -0
  50. data/lib/pickle/config.rb +49 -0
  51. data/lib/pickle/email.rb +87 -0
  52. data/lib/pickle/email/parser.rb +18 -0
  53. data/lib/pickle/email/world.rb +13 -0
  54. data/lib/pickle/parser.rb +65 -0
  55. data/lib/pickle/parser/matchers.rb +87 -0
  56. data/lib/pickle/path.rb +45 -0
  57. data/lib/pickle/path/world.rb +5 -0
  58. data/lib/pickle/session.rb +244 -0
  59. data/lib/pickle/session/parser.rb +34 -0
  60. data/lib/pickle/version.rb +3 -0
  61. data/lib/pickle/world.rb +14 -0
  62. data/lib/spbtv_pickle.rb +1 -0
  63. data/rails_generators/pickle/pickle_generator.rb +31 -0
  64. data/rails_generators/pickle/templates/email.rb +21 -0
  65. data/rails_generators/pickle/templates/email_steps.rb +65 -0
  66. data/rails_generators/pickle/templates/paths.rb +47 -0
  67. data/rails_generators/pickle/templates/pickle.rb +29 -0
  68. data/rails_generators/pickle/templates/pickle_steps.rb +105 -0
  69. data/spbtv_pickle.gemspec +38 -0
  70. data/spec/pickle/adapter_spec.rb +203 -0
  71. data/spec/pickle/config_spec.rb +112 -0
  72. data/spec/pickle/email/parser_spec.rb +51 -0
  73. data/spec/pickle/email_spec.rb +187 -0
  74. data/spec/pickle/parser/matchers_spec.rb +70 -0
  75. data/spec/pickle/parser_spec.rb +165 -0
  76. data/spec/pickle/path_spec.rb +120 -0
  77. data/spec/pickle/session_spec.rb +448 -0
  78. data/spec/pickle_spec.rb +24 -0
  79. data/spec/spec_helper.rb +78 -0
  80. metadata +370 -0
@@ -0,0 +1,4 @@
1
+ Pickle.configure do |c|
2
+ c.map 'I', :to => 'user: "me"'
3
+ c.map 'killah fork', :to => 'fancy fork: "of cornwood"'
4
+ end
data/init.rb ADDED
File without changes
@@ -0,0 +1,44 @@
1
+ require 'rails/generators'
2
+
3
+ class PickleGenerator < Rails::Generators::Base
4
+ desc "Generates Pickle step files."
5
+
6
+ # Use the same templates as Rails 2 generator
7
+ source_root File.expand_path("../../../rails_generators/pickle/templates", __FILE__)
8
+
9
+ class_option :paths, :desc => "Generate features/support/paths.rb file.", :type => :boolean
10
+ class_option :email, :desc => "Generate features/step_definitions/email_steps.rb file", :type => :boolean
11
+
12
+ def create_directories
13
+ empty_directory "features/step_definitions"
14
+ empty_directory "features/support"
15
+ end
16
+
17
+ def copy_pickle_steps_file
18
+ template "pickle_steps.rb", "features/step_definitions/pickle_steps.rb"
19
+ template "pickle.rb", "features/support/pickle.rb"
20
+ end
21
+
22
+ def copy_paths_file
23
+ return unless options.paths?
24
+ template "paths.rb", "features/support/paths.rb"
25
+ end
26
+
27
+ def copy_email_steps_file
28
+ return unless options.email?
29
+ template "email_steps.rb", "features/step_definitions/email_steps.rb"
30
+ template "email.rb", "features/support/email.rb"
31
+ end
32
+
33
+
34
+ private
35
+
36
+ # Compatibility methods for Rails 2 templates
37
+ def pickle_path
38
+ options.paths?
39
+ end
40
+
41
+ def pickle_email
42
+ options.email?
43
+ end
44
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_support'
2
+ require 'pickle/version'
3
+ require 'pickle/adapter'
4
+ require 'pickle/config'
5
+ require 'pickle/parser'
6
+ require 'pickle/session'
7
+ require 'pickle/session/parser'
8
+
9
+ # make the parser aware of models in the session (for fields refering to models)
10
+ Pickle::Parser.send :include, Pickle::Session::Parser
11
+
12
+ module Pickle
13
+ class << self
14
+ def config
15
+ @config ||= Config.new
16
+ end
17
+
18
+ def configure(&block)
19
+ config.configure(&block)
20
+ end
21
+
22
+ def parser(options = {})
23
+ @parser ||= Parser.new({:config => config}.merge(options))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,183 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module Pickle
4
+ # Abstract Factory adapter class, if you have a factory type setup, you
5
+ # can easily create an adaptor to make it work with Pickle.
6
+ #
7
+ # The factory adaptor must have a #factories class method that returns
8
+ # its instances, and each instance must respond to:
9
+ #
10
+ # #name : identifies the factory by name (default is attr_reader)
11
+ # #klass : returns the associated model class for this factory (default is attr_reader)
12
+ # #create(attrs = {}) : returns a newly created object
13
+ class Adapter
14
+ attr_reader :name, :klass
15
+
16
+ def create(attrs = {})
17
+ raise NotImplementedError, "create and return an object with the given attributes"
18
+ end
19
+
20
+ if respond_to?(:class_attribute)
21
+ class_attribute :model_classes
22
+ else
23
+ cattr_writer :model_classes
24
+ end
25
+
26
+ self.model_classes = nil
27
+
28
+ # Include this module into your ORM adapter
29
+ # this will register the adapter with pickle and it will be picked up for you
30
+ # To create an adapter you should create an inner constant "PickleAdapter"
31
+ #
32
+ # e.g. ActiveRecord::Base::PickleAdapter
33
+ #
34
+ # @see pickle/adapters/active_record
35
+ # @see pickle/adapters/datamapper
36
+ # @see pickle/adapters/mongoid
37
+ module Base
38
+ def self.included(base)
39
+ adapters << base
40
+ end
41
+
42
+ # A collection of registered adapters
43
+ def self.adapters
44
+ @@adapters ||= []
45
+ end
46
+ end
47
+
48
+ class << self
49
+ def factories
50
+ raise NotImplementedError, "return an array of factory adapter objects"
51
+ end
52
+
53
+ def model_classes
54
+ @@model_classes ||= self::Base.adapters.map{ |a| a.model_classes }.flatten
55
+ end
56
+
57
+ # Returns the column names for the given ORM model class.
58
+ def column_names(klass)
59
+ klass.const_get(:PickleAdapter).column_names(klass)
60
+ end
61
+
62
+ def get_model(klass, id)
63
+ klass.const_get(:PickleAdapter).get_model(klass, id)
64
+ end
65
+
66
+ def find_first_model(klass, conditions)
67
+ klass.const_get(:PickleAdapter).find_first_model(klass, conditions)
68
+ end
69
+
70
+ def find_all_models(klass, conditions)
71
+ klass.const_get(:PickleAdapter).find_all_models(klass, conditions)
72
+ end
73
+
74
+ def create_model(klass, attributes)
75
+ klass.const_get(:PickleAdapter).create_model(klass, attributes)
76
+ end
77
+ end
78
+
79
+ # machinist adapter
80
+ class Machinist < Adapter
81
+ def self.factories
82
+ factories = []
83
+ model_classes.each do |klass|
84
+ if blueprints = klass.instance_variable_get('@blueprints')
85
+ blueprints.keys.each {|blueprint| factories << new(klass, blueprint)}
86
+ end
87
+ end
88
+ factories
89
+ end
90
+
91
+ def initialize(klass, blueprint)
92
+ @klass, @blueprint = klass, blueprint
93
+ @name = @klass.name.underscore.gsub('/','_')
94
+ @name = "#{@blueprint}_#{@name}" unless @blueprint == :master
95
+ end
96
+
97
+ def create(attrs = {})
98
+ @klass.send(:make!, @blueprint, attrs)
99
+ end
100
+ end
101
+
102
+ # factory-girl adapter
103
+ class FactoryGirl < Adapter
104
+ def self.factories
105
+ if defined? ::FactoryGirl
106
+ factories = []
107
+ ::FactoryGirl.factories.each do |factory|
108
+ factory.names.each do |name|
109
+ factories << new(factory, name)
110
+ end
111
+ end
112
+ factories
113
+ else
114
+ (::Factory.factories.values rescue []).map {|factory| new(factory)}
115
+ end
116
+ end
117
+
118
+ def initialize(factory, factory_name)
119
+ if defined? ::FactoryGirl
120
+ @klass, @name = factory.build_class, factory_name.to_s
121
+ else
122
+ @klass, @name = factory.build_class, factory.factory_name.to_s
123
+ end
124
+ end
125
+
126
+ def create(attrs = {})
127
+ if defined? ::FactoryGirl
128
+ ::FactoryGirl.create(@name, attrs)
129
+ else
130
+ Factory(@name, attrs)
131
+ end
132
+ end
133
+
134
+ def build(attrs = {})
135
+ if defined? ::FactoryGirl
136
+ ::FactoryGirl.build(@name, attrs)
137
+ else
138
+ Factory.build(@name, attrs)
139
+ end
140
+ end
141
+ end
142
+
143
+ # fabrication adapter
144
+ class Fabrication < Adapter
145
+ def self.factories
146
+ if defined? ::Fabrication
147
+ ::Fabrication.manager.load_definitions if ::Fabrication.manager.schematics.empty?
148
+ ::Fabrication.manager.schematics.map { |name, klass| new([name, klass]) }
149
+ else
150
+ []
151
+ end
152
+ end
153
+
154
+ def initialize(factory)
155
+ if defined? ::Fabrication
156
+ @klass, @name = factory[1].klass, factory[0].to_s
157
+ end
158
+ end
159
+
160
+ def create(attrs = {})
161
+ if defined? ::Fabrication
162
+ Fabricate(@name.to_sym, attrs)
163
+ end
164
+ end
165
+ end
166
+
167
+ # ORM adapter. If you have no factory adapter, you can use this adapter to
168
+ # use your orm as 'factory' - ie create objects
169
+ class Orm < Adapter
170
+ def self.factories
171
+ model_classes.map{|k| new(k)}
172
+ end
173
+
174
+ def initialize(klass)
175
+ @klass, @name = klass, klass.name.underscore.gsub('/','_')
176
+ end
177
+
178
+ def create(attrs = {})
179
+ Pickle::Adapter.create_model(@klass, attrs)
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,67 @@
1
+ begin
2
+ require 'activerecord'
3
+ rescue LoadError
4
+ require 'active_record'
5
+ end
6
+
7
+ class ActiveRecord::Base
8
+ module PickleAdapter
9
+ include Pickle::Adapter::Base
10
+
11
+ # Do not consider these to be part of the class list
12
+ def self.except_classes
13
+ @@except_classes ||= [
14
+ "CGI::Session::ActiveRecordStore::Session",
15
+ "ActiveRecord::SessionStore::Session"
16
+ ]
17
+ end
18
+
19
+ # Gets a list of the available models for this adapter
20
+ def self.model_classes
21
+ if ::ActiveRecord::Base.respond_to?(:descendants)
22
+ klasses = ::ActiveRecord::Base.descendants # Rails 3, 4
23
+ else
24
+ klasses = ::ActiveRecord::Base.subclasses # Rails 2
25
+ end
26
+
27
+ klasses.select do |klass|
28
+ !klass.abstract_class? && klass.table_exists? && !except_classes.include?(klass.name)
29
+ end
30
+ end
31
+
32
+ # get a list of column names for a given class
33
+ def self.column_names(klass)
34
+ klass.column_names
35
+ end
36
+
37
+ # Get an instance by id of the model
38
+ def self.get_model(klass, id)
39
+ klass.find(id)
40
+ end
41
+
42
+ # Find the first instance matching conditions
43
+ def self.find_first_model(klass, conditions)
44
+ if defined? ::ActiveRecord::Relation
45
+ klass.where(conditions).first # Rails 3, 4
46
+ else
47
+ klass.find(:first,
48
+ :conditions => conditions) # Rails 2
49
+ end
50
+ end
51
+
52
+ # Find all models matching conditions
53
+ def self.find_all_models(klass, conditions)
54
+ if defined? ::ActiveRecord::Relation
55
+ klass.where(conditions) # Rails 3, 4
56
+ else
57
+ klass.find(:all,
58
+ :conditions => conditions) # Rails 2
59
+ end
60
+ end
61
+
62
+ # Create a model using attributes
63
+ def self.create_model(klass, attributes)
64
+ klass.create!(attributes)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,42 @@
1
+ require 'dm-core'
2
+
3
+ module DataMapper::Resource
4
+ module PickleAdapter
5
+ include Pickle::Adapter::Base
6
+
7
+ # Do not consider these to be part of the class list
8
+ def self.except_classes
9
+ @@except_classes ||= []
10
+ end
11
+
12
+ # Gets a list of the available models for this adapter
13
+ def self.model_classes
14
+ ::DataMapper::Model.descendants.to_a.select{|k| !except_classes.include?(k.name)}
15
+ end
16
+
17
+ # get a list of column names for a given class
18
+ def self.column_names(klass)
19
+ klass.properties.map(&:name)
20
+ end
21
+
22
+ # Get an instance by id of the model
23
+ def self.get_model(klass, id)
24
+ klass.get(id)
25
+ end
26
+
27
+ # Find the first instance matching conditions
28
+ def self.find_first_model(klass, conditions)
29
+ klass.first(conditions)
30
+ end
31
+
32
+ # Find all models matching conditions
33
+ def self.find_all_models(klass, conditions)
34
+ klass.all(conditions)
35
+ end
36
+
37
+ # Create a model using attributes
38
+ def self.create_model(klass, attributes)
39
+ klass.create(attributes)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,54 @@
1
+ require 'mongoid'
2
+
3
+ module Mongoid
4
+ module Document
5
+ module PickleAdapter
6
+ include Pickle::Adapter::Base
7
+
8
+ # Do not consider these to be part of the class list
9
+ def self.except_classes
10
+ @@except_classes ||= []
11
+ end
12
+
13
+ # Gets a list of the available models for this adapter
14
+ def self.model_classes
15
+ ObjectSpace.each_object(Class).to_a.select do |klass|
16
+ klass.name && klass.ancestors.include?(Mongoid::Document)
17
+ end
18
+ end
19
+
20
+ # get a list of column names for a given class
21
+ def self.column_names(klass)
22
+ klass.try(:fields).try(:keys) || []
23
+ end
24
+
25
+ # Get an instance by id of the model
26
+ def self.get_model(klass, id)
27
+ klass.find(id)
28
+ end
29
+
30
+ # Find the first instance matching conditions
31
+ def self.find_first_model(klass, conditions)
32
+ if defined? ::Mongoid::Criteria
33
+ klass.where(conditions).first
34
+ else
35
+ klass.first(:conditions => conditions)
36
+ end
37
+ end
38
+
39
+ # Find all models matching conditions
40
+ def self.find_all_models(klass, conditions)
41
+ if defined? ::Mongoid::Criteria
42
+ klass.where(conditions).to_a
43
+ else
44
+ klass.all(:conditions => conditions)
45
+ end
46
+ end
47
+
48
+ # Create a model with given attributes
49
+ def self.create_model(klass, attributes)
50
+ klass.create!(attributes)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,49 @@
1
+ module Pickle
2
+ class Config
3
+ attr_writer :adapters, :factories, :mappings, :predicates
4
+
5
+ def initialize(&block)
6
+ configure(&block) if block_given?
7
+ end
8
+
9
+ def configure(&block)
10
+ yield(self)
11
+ end
12
+
13
+ def adapters
14
+ @adapters ||= [:machinist, :factory_girl, :fabrication, :orm]
15
+ end
16
+
17
+ def adapter_classes
18
+ adapters.map {|a| a.is_a?(Class) ? a : "pickle/adapter/#{a}".classify.constantize}
19
+ end
20
+
21
+ def factories
22
+ @factories ||= adapter_classes.reverse.inject({}) do |factories, adapter|
23
+ factories.merge(adapter.factories.inject({}){|h, f| h.merge(f.name => f)})
24
+ end
25
+ end
26
+
27
+ def predicates
28
+ @predicates ||= Pickle::Adapter.model_classes.map do |k|
29
+ k.public_instance_methods.select {|m| m =~ /\?$/} + Pickle::Adapter.column_names(k)
30
+ end.flatten.uniq
31
+ end
32
+
33
+ class Mapping < Struct.new(:search, :replacement)
34
+ end
35
+
36
+ def mappings
37
+ @mappings ||= []
38
+ end
39
+
40
+ # Usage: map 'me', 'myself', 'I', :to => 'user: "me"'
41
+ def map(*args)
42
+ options = args.extract_options!
43
+ raise ArgumentError, "Usage: map 'search' [, 'search2', ...] :to => 'replace'" unless args.any? && options[:to].is_a?(String)
44
+ args.each do |search|
45
+ self.mappings << Mapping.new(search, options[:to])
46
+ end
47
+ end
48
+ end
49
+ end