Permalink
Browse files

Initial release of pickle (Expermental: in development)

  • Loading branch information...
0 parents commit d360c294c817627a4b0991408ff664a1be50bb01 @ianwhite committed Oct 16, 2008
@@ -0,0 +1,4 @@
+doc/*
+garlic
+garlic.rb
+garlic_example.txt
1 README
@@ -0,0 +1,51 @@
+= Experimental: In development
+
+Stick this in vendor/plugins to have cucumber steps that create your models easily from factory_girl.
+
+References to the models are stored, not for the purpose of checking the db (although you could use it for
+that), but for enabling easy reference to urls, and for building complex givens
+
+== Example
+
+If you have a user model, which has admin? and moderator? predicate methods
+and let's say you have an :admin, :user, and :moderator factory, you can do this in a Scenario:
+
+ And an admin exists
+ And a moderator exists
+
+ # the following is just to show how refs work, obviously you'd not want to test this
+ Then the moderator should be a moderator
+ And the admin should be an admin
+ And the moderator should not be an admin
+
+== Usage
+
+in features/env.rb
+
+require 'pickle/steps'
+
+== API
+
+=== Creating regexps
+
+For matching english versions of model names you get
+
+ match_model
+
+ Given /^(#{match_model}) exists$/
+
+For matching a field string, you get
+
+ match_fields
+
+ Given /^(#{match_model}) exists with (#{match_fields})/
+
+Take a look at pickle/steps.rb for more examples
+
+=== Creating and tracking models
+
+ #create_model(<model ref>[, <field string>])
+
+ #find_model(<model ref>[, <field string>])
+
+ #model(<model ref>)
101 Rakefile
@@ -0,0 +1,101 @@
+# use pluginized rpsec if it exists
+rspec_base = File.expand_path(File.dirname(__FILE__) + '/../rspec/lib')
+$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base) and !$LOAD_PATH.include?(rspec_base)
+
+require 'spec/rake/spectask'
+require 'spec/rake/verify_rcov'
+require 'rake/rdoctask'
+
+plugin_name = 'pickle'
+
+task :default => :spec
+
+task :cruise do
+ # run the garlic task, capture the output, if succesful make the docs and copy them to ardes
+ begin
+ sh "rake garlic:all > garlic_report.txt"
+
+ # send abridged rpeort
+ report = File.read('garlic_report.txt').sub(/^.*?==========/m, '==========')
+ report = "garlic report for #{plugin_name}\n#{`git log -n 1 --pretty=oneline --no-color`}\n" + report
+ File.open('garlic_report.txt', 'w+') {|f| f << report }
+ sh "scp -i ~/.ssh/ardes garlic_report.txt ardes@ardes.com:~/subdomains/plugins/httpdocs/doc/#{plugin_name}_garlic_report.txt"
+
+ # build doc and send that
+ cd "garlic/work/edge/vendor/plugins/#{plugin_name}" do
+ sh "rake doc:all"
+ sh "scp -i ~/.ssh/ardes -r doc ardes@ardes.com:~/subdomains/plugins/httpdocs/doc/#{plugin_name}"
+ end
+
+ ensure
+ puts File.read('garlic_report.txt')
+ end
+end
+
+desc "Run the specs for #{plugin_name}"
+Spec::Rake::SpecTask.new(:spec) do |t|
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ t.spec_opts = ["--colour"]
+end
+
+namespace :spec do
+ desc "Generate RCov report for #{plugin_name}"
+ Spec::Rake::SpecTask.new(:rcov) do |t|
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ t.rcov = true
+ t.rcov_dir = 'doc/coverage'
+ t.rcov_opts = ['--text-report', '--exclude', "spec/,rcov.rb,#{File.expand_path(File.join(File.dirname(__FILE__),'../../..'))}"]
+ end
+
+ namespace :rcov do
+ desc "Verify RCov threshold for #{plugin_name}"
+ RCov::VerifyTask.new(:verify => "spec:rcov") do |t|
+ t.threshold = 100.0
+ t.index_html = File.join(File.dirname(__FILE__), 'doc/coverage/index.html')
+ end
+ end
+
+ desc "Generate specdoc for #{plugin_name}"
+ Spec::Rake::SpecTask.new(:doc) do |t|
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ t.spec_opts = ["--format", "specdoc:SPECDOC"]
+ end
+
+ namespace :doc do
+ desc "Generate html specdoc for #{plugin_name}"
+ Spec::Rake::SpecTask.new(:html => :rdoc) do |t|
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ t.spec_opts = ["--format", "html:doc/rspec_report.html", "--diff"]
+ end
+ end
+end
+
+task :rdoc => :doc
+task "SPECDOC" => "spec:doc"
+
+desc "Generate rdoc for #{plugin_name}"
+Rake::RDocTask.new(:doc) do |t|
+ t.rdoc_dir = 'doc'
+ t.main = 'README'
+ t.title = "#{plugin_name}"
+ t.template = ENV['RDOC_TEMPLATE']
+ t.options = ['--line-numbers', '--inline-source', '--all']
+ t.rdoc_files.include('README.rdoc', 'SPECDOC', 'MIT-LICENSE', 'CHANGELOG')
+ t.rdoc_files.include('lib/**/*.rb')
+end
+
+namespace :doc do
+ desc "Generate all documentation (rdoc, specdoc, specdoc html and rcov) for #{plugin_name}"
+ task :all => ["spec:doc:html", "spec:doc", "spec:rcov", "doc"]
+end
+
+# load up garlic if it's here
+if File.directory?(File.join(File.dirname(__FILE__), 'garlic'))
+ require File.join(File.dirname(__FILE__), 'garlic/lib/garlic_tasks')
+ require File.join(File.dirname(__FILE__), 'garlic')
+end
+
+desc "clone the garlic repo (for running ci tasks)"
+task :get_garlic do
+ sh "git clone git://github.com/ianwhite/garlic.git garlic"
+end
No changes.
@@ -0,0 +1,3 @@
+require 'pickle/parser'
+require 'pickle/session'
+require 'pickle/injector'
@@ -0,0 +1,18 @@
+module Pickle
+ module Injector
+ def self.inject(session, options = {})
+ target = options[:into] || ActionController::Integration::Session
+ session_name = session.name.underscore.gsub('/','_')
+
+ target.class_eval <<-end_eval, __FILE__, __LINE__
+ def #{session_name}
+ @#{session_name} ||= #{session.name}.new
+ end
+ end_eval
+
+ delegate_methods = session.instance_methods - Object.instance_methods
+ delegate_methods << {:to => session_name}
+ target.delegate *delegate_methods
+ end
+ end
+end
@@ -0,0 +1,106 @@
+require 'factory_girl'
+
+module Pickle
+ module Parser
+ MatchOrdinal = '(?:\d+(?:st|nd|rd|th))'
+ CaptureOrdinal = '(?:(\d+)(?:st|nd|rd|th))'
+ MatchIndex = "(?:first|last|#{MatchOrdinal})"
+ MatchPrefix = '(?:1 |a |an |the |that )'
+ MatchName = '(?:: ".*?")'
+ CaptureName = '(?:: "(.*?)")'
+ MatchField = '(?:\w+: ".*?")'
+ MatchFields = "(?:#{MatchField}, )*#{MatchField}"
+
+ module Matchers
+ def match_model_name
+ "(?:#{Parser.model_match_names.join('|')})"
+ end
+
+ def match_model
+ matcher = '(?:'
+ matcher += '(?:' + Parser.mappings.map {|m| "(?:#{m.first})"}.join('|') + ')|' if Parser.mappings.any?
+ matcher += "#{MatchPrefix}?"
+ matcher += "(?:"
+ matcher += "(?:#{MatchIndex} )?#{match_model_name}"
+ matcher += "|"
+ matcher += "#{match_model_name}#{MatchName}?"
+ matcher += ")"
+ matcher += ")"
+ end
+ end
+
+ include Matchers
+ extend Matchers
+
+ mattr_accessor :mappings
+ self.mappings = []
+
+ class << self
+ attr_accessor_with_default :active_record_names do
+ Dir["#{RAILS_ROOT}/app/models/**/**"].reject{|f| f =~ /observer.rb$/}.map{|f| f.sub("#{RAILS_ROOT}/app/models/",'').sub(".rb",'')}
+ end
+
+ attr_accessor_with_default :factory_names do
+ Factory.factories.keys.map(&:to_s)
+ end
+
+ attr_accessor_with_default :model_names do
+ (active_record_names | factory_names)
+ end
+
+ attr_accessor_with_default :model_match_names do
+ model_names.sort.map{|n| n.gsub('_','[_ ]').gsub('/','[\/: ]')}
+ end
+
+ def map(search, options)
+ raise ArgumentError, "Usage: map 'search', :to => 'replace'" unless search.is_a?(String) && options[:to].is_a?(String)
+ self.mappings << [search, options[:to]]
+ end
+
+ def apply_mappings!(string)
+ self.mappings.each do |(search, replace)|
+ string.sub! /^(?:#{search})$/, replace
+ end
+ end
+ end
+
+ # given a string like 'foo: "bar", bar: "baz"' returns {"foo" => "bar", "bar" => "baz"}
+ def parse_fields(fields)
+ fields.to_s.split(',').inject({}) do |m, field|
+ m.merge(parse_field(field))
+ end
+ end
+
+ # given a string like 'foo: "bar"' returns {key => value}
+ def parse_field(field)
+ key, val = *field.squish.split(': ')
+ { key => val.sub(/^"/,'').sub(/"$/,'') }
+ end
+
+ # returns really underscored name
+ def pickle_name(str)
+ str.to_s.gsub(' ','_').underscore
+ end
+
+ def parse_index(index)
+ case index
+ when '', /last/ then -1
+ when /#{CaptureOrdinal}/ then $1.to_i - 1
+ when /first/ then 0
+ end
+ end
+
+ private
+ # return [factory, name or integer index]
+ def parse_model(name)
+ Parser.apply_mappings!(name)
+ if /(#{match_model_name})#{CaptureName}$/ =~ name
+ [pickle_name($1), pickle_name($2)]
+ elsif /(#{MatchIndex}) (#{match_model_name})$/ =~ name
+ [pickle_name($2), parse_index($1)]
+ else
+ /(#{match_model_name})#{CaptureName}?$/ =~ name && [pickle_name($1), pickle_name($2)]
+ end
+ end
+ end
+end
@@ -0,0 +1,72 @@
+module Pickle
+ class Session
+ include Parser
+
+ def create_model(a_model_name, fields = nil)
+ factory, name = *parse_model(a_model_name)
+ raise ArgumentError, "Can't create a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
+ record = Factory(factory, parse_fields(fields))
+ store_model(factory, name, record)
+ end
+
+ def find_model(a_model_name, fields)
+ model, name = *parse_model(a_model_name)
+ record = model.classify.constantize.find :first, :conditions => parse_fields(fields)
+ store_model(model, name, record)
+ end
+
+ # return the original model stored by create_model or find_model
+ def original_model(a_model_name)
+ factory, name_or_index = *parse_model(a_model_name)
+
+ if name_or_index.blank?
+ models_by_factory(factory).last
+ elsif name_or_index.is_a?(Integer)
+ models_by_factory(factory)[name_or_index]
+ else
+ models_by_name(factory)[name_or_index]
+ end
+ end
+
+ # return a newly selected model
+ def model(a_model_name)
+ if model = original_model(a_model_name)
+ model.class.find(model.id)
+ end
+ end
+
+ # return all original models of specified type
+ def original_models(factory)
+ models_by_factory(factory)
+ end
+
+ # return all models of specified type (freshly selected from the database)
+ def models(factory)
+ original_models(factory).map do |model|
+ model.class.find(model.id)
+ end
+ end
+
+ private
+ def models_by_name(factory)
+ @models_by_name ||= {}
+ @models_by_name[factory] ||= {}
+ end
+
+ def models_by_factory(factory)
+ @models_by_factory ||= {}
+ @models_by_factory[factory] ||= []
+ end
+
+ # if the factory name != the model name, store under both names
+ def store_model(factory, name, record)
+ store_record(pickle_name(record.class.name), name, record) if pickle_name(record.class.name) != factory
+ store_record(factory, name, record)
+ end
+
+ def store_record(factory, name, record)
+ models_by_name(factory)[name] = record
+ models_by_factory(factory) << record
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit d360c29

Please sign in to comment.