From 0376067cf4382e6a8db5650079de0e188305e656 Mon Sep 17 00:00:00 2001 From: Simon Rozet Date: Sun, 22 Jun 2008 20:26:30 +0200 Subject: [PATCH] Install the `skinny_spec' plugin. It's basically a set of rspec macro allowing you to write thing such as `it_should_find_and_assign :users'. See for more informations. It's recommended to install the `ruby2ruby' gem to have nicer error messages, but it is not required to work. @@ update README_FOR_DEVELOPERS accordingly. --- spec/spec_helper.rb | 1 + vendor/plugins/skinny_spec/.gitignore | 2 + vendor/plugins/skinny_spec/README.rdoc | 267 ++++++++++ vendor/plugins/skinny_spec/Rakefile | 11 + .../additional/helper_overrides.txt | 58 +++ .../skinny_scaffold_generator.rb | 93 ++++ .../skinny_scaffold/templates/controller.rb | 105 ++++ .../templates/controller_spec.rb | 116 +++++ .../skinny_scaffold/templates/form.html.erb | 25 + .../skinny_scaffold/templates/form.html.haml | 18 + .../templates/form.html_spec.rb | 41 ++ .../skinny_scaffold/templates/helper.rb | 2 + .../skinny_scaffold/templates/helper_spec.rb | 5 + .../skinny_scaffold/templates/index.html.erb | 31 ++ .../skinny_scaffold/templates/index.html.haml | 23 + .../templates/index.html_spec.rb | 15 + .../templates/index_partial.html.erb | 12 + .../templates/index_partial.html.haml | 11 + .../templates/index_partial.html_spec.rb | 32 ++ .../skinny_scaffold/templates/migration.rb | 14 + .../skinny_scaffold/templates/model.rb | 2 + .../skinny_scaffold/templates/model_spec.rb | 25 + .../skinny_scaffold/templates/show.html.erb | 15 + .../skinny_scaffold/templates/show.html.haml | 13 + .../templates/show.html_spec.rb | 32 ++ vendor/plugins/skinny_spec/init.rb | 3 + .../lib/lucky_sneaks/common_spec_helpers.rb | 46 ++ .../controller_request_helpers.rb | 67 +++ .../lucky_sneaks/controller_spec_helpers.rb | 435 +++++++++++++++++ .../lucky_sneaks/controller_stub_helpers.rb | 199 ++++++++ .../lib/lucky_sneaks/model_spec_helpers.rb | 326 +++++++++++++ .../lib/lucky_sneaks/view_spec_helpers.rb | 460 ++++++++++++++++++ vendor/plugins/skinny_spec/lib/skinny_spec.rb | 26 + 33 files changed, 2531 insertions(+) create mode 100644 vendor/plugins/skinny_spec/.gitignore create mode 100644 vendor/plugins/skinny_spec/README.rdoc create mode 100644 vendor/plugins/skinny_spec/Rakefile create mode 100644 vendor/plugins/skinny_spec/additional/helper_overrides.txt create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml create mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb create mode 100644 vendor/plugins/skinny_spec/init.rb create mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb create mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb create mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb create mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb create mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb create mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb create mode 100644 vendor/plugins/skinny_spec/lib/skinny_spec.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 938dd7b4..a9acc7d3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,6 +4,7 @@ ENV["RAILS_ENV"] = "test" require File.expand_path(File.dirname(__FILE__) + "/../config/environment") require 'spec' require 'spec/rails' +require 'skinny_spec' Spec::Runner.configure do |config| # If you're not using ActiveRecord you should remove these diff --git a/vendor/plugins/skinny_spec/.gitignore b/vendor/plugins/skinny_spec/.gitignore new file mode 100644 index 00000000..28f7b7da --- /dev/null +++ b/vendor/plugins/skinny_spec/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +doc \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/README.rdoc b/vendor/plugins/skinny_spec/README.rdoc new file mode 100644 index 00000000..49cfbf60 --- /dev/null +++ b/vendor/plugins/skinny_spec/README.rdoc @@ -0,0 +1,267 @@ += Skinny Spec + +Skinny Spec is a collection of spec helper methods designed to help trim the fat and DRY up +some of the bloat that sometimes results from properly specing your classes and templates. + +== Requirements and Recommendations + +Obviously you'll need to be using RSpec[http://github.com/dchelimsky/rspec/tree/master] and +Rspec-Rails[http://github.com/dchelimsky/rspec-rails/tree/master] as your testing framework. + +Skinny Spec was originally designed [and best enjoyed] if you're using +Haml[http://github.com/nex3/haml/tree/master] and +make_resourceful[http://github.com/rsl/make_resourceful/tree/master] but will default to +ERb and a facsimile of Rails' default scaffolding [for the views and controllers, respectively] +if Haml and/or make_resourceful are not available. I recommend using them though. :) + +In addition, Skinny Spec uses Ruby2Ruby to make nicer expectation messages and you'll want to +have that installed as well. It's not a dependency or anything but it is highly +recommended. + +== Setup + +Once you've installed the plugin in your app's vendor/plugins folder, you're ready to rock! +Skinny Spec includes itself into the proper RSpec classes so there's no configuration on your +part. Sweet! + +== Usage + +The simplest way to use Skinny Specs is to generate a resource scaffold: + + script/generate skinny_scaffold User + +This command takes the usual complement of attribute definitions like +script/generate scaffold. Then have a look at the generated files (particularly the +specs) to see what's new and different with Skinny Spec. + +=== Controller Specs + +Let's look at the controller specs. + + describe UsersController do + def valid_attributes(args = {}) + { + # Add valid attributes for the your params[:user] here! + }.merge(args) + end + + describe "GET :index" do + before(:each) do + @users = stub_index(User) + end + + it_should_find_and_assign :users + it_should_render :template, "index" + end + + # ... + + describe "POST :create" do + describe "when successful" do + before(:each) do + @user = stub_create(User) + end + + it_should_initialize_and_save :user + it_should_redirect_to { user_url(@user) } + end + + # ... + +First thing you should see is a method definition for +valid_attributes. This will be used later by the create and update +specs to more accurately represent how the controller works in actual practice by supplying +somewhat real data for the params coming from the HTML forms. + +Next we find an example group for GET :index. That stub_index method there +does a lot of work behind the curtain. I'll leave it up to you to check the documentation for it +(and its brothers and sister methods like stub_new) but I will point out that the +methods named stub_controller_method should only be used for stubbing and +mocking the main object of the method. To create mocks for other ancillary objects, please +use stub_find_all, stub_find_one, and stub_initialize. The reason +for this is because the former methods actually save us a step by defining an implicit +controller method request. If you add a new method to your resource routing, you'll want to +use the helper method define_request in those example groups to define an explicit +request. You can also define a method called shared_request to "share a +define_request" across shared describe blocks, like so: + + describe "POST :create" do + def shared_request + post :create + end + + describe "when successful" do + # ... + end + + describe "when unsuccessful" do + # ... + end + end + +Note: When you're adding longer, more complicated controller specs you can still leverage +implicit and shared requests by calling do_request in your spec as in the following +example: + + # Let's assume this controller is _not_ CategoriesController + # and that loading the categories isn't part of the default actions + describe "GET :index" do + before(:each) do + @categories = stub_find_all(Category) + end + + it "should preload categories" do + Category.should_receive(:find).with(:all) + do_request + end + + it "should assign @categories" do + do_request + assigns[:categories].should == @categories + end + end + +Finally we get to the meat of the spec and of Skinny Specs itself: the actual expectations. +The first thing you'll notice is the use of example group (read: "describe" block) level methods +instead of the usual example (read: "it") blocks. Using this helper at the example group level +saves us three lines over using an example block. (If this isn't significant to you, this is +probably the wrong plugin for you as well. Sorry.) Note that none of these methods use the +instance variables defined in the "before" block because they are all nil at the example block +level. Let's look at a sample method to see how it works: + + it_should_find_and_assign :users + +This actually wraps two different expectations: one that User.should_receive(:find).with(:all) +and another that the instance variable @users is assigned with the return value from that finder call. +If you need to add more detailed arguments to the find, you can easily break this into two different +expectations like: + + it_should_find :users, :limit => 2 + it_should_assign :users + +See the documentation for the it_should_find for more information. You might have guessed that +it_should_initialize_assign and it_should_render_template work in a similar +fashion and you'd be right. Again, see the documentation for these individual methods for more +information. Lots of information in those docs. + +A useful helper method that doesn't appear in any of the scaffolding is with_default_restful_actions +which takes a block and evaluates it for each of the RESTful controller actions. Very useful for +spec'ing that these methods redirect to the login page when the user isn't logged in, for example. This +method is designed to be used inside an example like so: + + describe "when not logged in" do + it "should redirect all requests to the login page" do + with_default_restful_actions do + response.should redirect_to(login_url) + end + end + end + +Before we're through with the controller specs, let me point out one more important detail. In +order to use it_should_redirect_to we have to send the routing inside a block argument +there so it can be evaluated in the example context instead of the example group, where it +completely blows up. This methodology is used anywhere routing is referred to in a "skinny", +example group level spec. + +=== View Specs + +Now let's move to the view specs! + + describe "/users/form.html.haml" do + before(:each) do + @user = mock_and_assign(User, :stub => { + :name => "foo", + :birthday => 1.week.ago, + :adult => false + }) + end + + it_should_have_form_for :user + + it_should_allow_editing :user, :name + it_should_allow_editing :user, :birthday + it_should_allow_editing :user, :adult + + it_should_link_to_show :user + it_should_link_to { users_path } + end + +Like the special stub_index methods in the controller +specs, the view specs have a shorthand mock and stub helpers: mock_and_assign and +mock_and_assign_collection. These are well documented so please check them out. + +There are also some really nice helper methods that I'd like point out. First is +it_should_have_form_for. This is a really good convenience wrapper that basically wraps +the much longer: + + it "should use form_for to generate the proper form action and options" do + template.should_receive(:form_for).with(@user) + do_render + end + +Next up is the it_should_allow_editing helper. I love this method the most because it +really helps DRY up that view spec while at the same time being amazingly unbrittle. Instead of +creating an expectation for a specific form element, this method creates a generalized expectation +that there's a form element with the name attribute set in such away that it will +generate the proper params to use in the controller to edit or create the instance. +Check out the docs and the source for more information on this. Also check out +it_should_have_form_element_for which is roughly equivalent for those times when you use +form_tag instead. + +Finally let's look at those it_should_link_to_controller_method helpers. +These methods (and there's one each for the controller methods +new, edit, show, and delete) point to instance variables +which you should be created in the "before" blocks with mock_and_assign. The other is +it_should_allow_editing which is likewise covered extensively in the documentation and +I will just point out here that, like it_should_link_to_edit and such, it takes a +symbol for the name of the instance variable it refers to and additionally takes +a symbol for the name of the attribute to be edited. + +Also note that, when constructing a long form example, instead of defining an instance variable +for the name of the template and calling render @that_template you can simply call +do_render which takes the name of the template from the outermost example group where +it is customarily stated. + +=== Model Specs + +Skinny Spec adds a matcher for the various ActiveRecord associations. On the example group level +you call them like: + + it_should_belong_to :manager + it_should_have_many :clients + +Within an example you can call them on either the class or the instance setup in the +"before" block. These are equivalent: + + @user.should belong_to(:group) + User.should belong_to(:group) + +I've also added some very basic validation helpers like it_should_validate_presence_of, +it_should_validate_uniqueness_of, it_should_not_mass_assign. Please consult +the documentation for more information. + +== Miscellaneous Notes + +In the scaffolding, I have used my own idiomatic Rails usage: + +* All controller actions which use HTML forms [new, edit, etc] use a shared + form and leverage form_for to its fullest by letting it create the appropriate + action and options. +* Some instances where you might expect link_to are button_to. This is to provide a common + interface element which can be styled the same instead of a mishmash of links and buttons and + inputs everywhere. To take full advantage of this, I usually override many of Rails' default + helpers with custom ones that all use actual HTML BUTTON elements which are much + easier to style than "button" typed INPUT. I've provided a text file in the + "additional" folder of this plugin which you can use in your ApplicationHelper. (I also + provide an optional override helper for the label method which uses + #titleize instead of humanize for stylistic reasons). +* Probably more that I can't think of. + +== Credits and Thanks + +Sections of this code were taken from or inspired by Rick Olsen's +rspec_on_rails_on_crack[http://github.com/technoweenie/rspec_on_rails_on_crack/tree/master]. +Also thanks and props to Hampton Catlin and Nathan Weizenbaum for the lovely and imminently useable +Haml and make_resourceful. Also also praises and glory to David Chelimsky and the Rspec crew. + +Also thanks to Don Petersen for his suggestions and fixes. \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/Rakefile b/vendor/plugins/skinny_spec/Rakefile new file mode 100644 index 00000000..b0adbc43 --- /dev/null +++ b/vendor/plugins/skinny_spec/Rakefile @@ -0,0 +1,11 @@ +require 'rake' +require 'rake/rdoctask' + +desc 'Generate documentation for the Skinny Spec plugin' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'doc' + rdoc.title = 'Skinny Spec' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('lib/**/*.rb') +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/additional/helper_overrides.txt b/vendor/plugins/skinny_spec/additional/helper_overrides.txt new file mode 100644 index 00000000..a15ec2d3 --- /dev/null +++ b/vendor/plugins/skinny_spec/additional/helper_overrides.txt @@ -0,0 +1,58 @@ +# Please insert these into your ApplicationHelper + +# Replacement for Rails' default submit_tag helper +# using HTML button element rather than HTML input element +def submit_tag(text, options = {}) + content_tag :button, text, options.merge(:type => :submit) +end + +# Replacement for Rails' default button_to helper +# using HTML button element rather than HTML input element +def button_to(name, options = {}, html_options = {}) + html_options = html_options.stringify_keys + convert_boolean_attributes!(html_options, %w( disabled )) + + method_tag = '' + if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s) + method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s) + end + + form_method = method.to_s == 'get' ? 'get' : 'post' + + request_token_tag = '' + if form_method == 'post' && protect_against_forgery? + request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) + end + + if confirm = html_options.delete("confirm") + html_options["onclick"] = "return #{confirm_javascript_function(confirm)};" + end + + url = options.is_a?(String) ? options : self.url_for(options) + name ||= url + + html_options.merge!("type" => "submit", "value" => name) + + "
" + + method_tag + content_tag("button", name, html_options) + request_token_tag + "
" +end + +# Replacement for Rails' default button_to_function helper +# using HTML button element rather than HTML input element +def button_to_function(name, *args, &block) + html_options = args.extract_options! + function = args[0] || '' + + html_options.symbolize_keys! + function = update_page(&block) if block_given? + content_tag(:button, name, html_options.merge({ + :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" + })) +end + +# Replacement for Rails' default label helper +# using String#titleize rather than String#humanize +def label(object_name, method, text = nil, options = {}) + text ||= method.to_s[].titleize + super +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb new file mode 100644 index 00000000..7f6f2b25 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb @@ -0,0 +1,93 @@ +class SkinnyScaffoldGenerator < Rails::Generator::NamedBase + attr_reader :controller_class_path, :controller_file_path, :controller_class_nesting, + :controller_class_nesting_depth, :controller_class_name, :controller_underscore_name, + :controller_plural_name, :template_language + alias_method :controller_file_name, :controller_underscore_name + alias_method :controller_singular_name, :controller_file_name + alias_method :controller_table_name, :controller_plural_name + + def initialize(runtime_args, runtime_options = {}) + super + + base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@name.pluralize) + @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name) + + if @controller_class_nesting.empty? + @controller_class_name = @controller_class_name_without_nesting + else + @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}" + end + end + + def manifest + record do |m| + # Check for class naming collisions + m.class_collisions controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper" + m.class_collisions class_path, "#{class_name}" + + # # Controller, helper, and views directories + m.directory File.join('app', 'views', controller_class_path, controller_file_name) + m.directory File.join('spec', 'views', controller_class_path, controller_file_name) + m.directory File.join('app', 'helpers', controller_class_path) + m.directory File.join('spec', 'helpers', controller_class_path) + m.directory File.join('app', 'controllers', controller_class_path) + m.directory File.join('spec', 'controllers', controller_class_path) + m.directory File.join('app', 'models', class_path) + m.directory File.join('spec', 'models', class_path) + + # Views + @template_language = defined?(Haml) ? "haml" : "erb" + %w{index show form}.each do |action| + m.template "#{action}.html.#{template_language}", + File.join('app/views', controller_class_path, controller_file_name, "#{action}.html.#{template_language}") + m.template "#{action}.html_spec.rb", + File.join('spec/views', controller_class_path, controller_file_name, "#{action}.html.#{template_language}_spec.rb") + end + m.template "index_partial.html.#{template_language}", + File.join('app/views', controller_class_path, controller_file_name, "_#{file_name}.html.#{template_language}") + m.template 'index_partial.html_spec.rb', + File.join('spec/views', controller_class_path, controller_file_name, "_#{file_name}.html.#{template_language}_spec.rb") + + # Helper + m.template 'helper.rb', + File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb") + m.template 'helper_spec.rb', + File.join('spec/helpers', controller_class_path, "#{controller_file_name}_helper_spec.rb") + + # Controller + m.template 'controller.rb', + File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") + m.template 'controller_spec.rb', + File.join('spec/controllers', controller_class_path, "#{controller_file_name}_controller_spec.rb") + + # Model + m.template 'model.rb', + File.join('app/models', class_path, "#{file_name}.rb") + m.template 'model_spec.rb', + File.join('spec/models', class_path, "#{file_name}_spec.rb") + + # Routing + m.route_resources controller_file_name + + unless options[:skip_migration] + m.migration_template( + 'migration.rb', 'db/migrate', + :assigns => { + :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}", + :attributes => attributes + }, + :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}" + ) + end + end + end + +protected + def banner + "Usage: #{$0} skinny_scaffold ModelName [field:type, field:type]" + end + + def model_name + class_name.demodulize + end +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb new file mode 100644 index 00000000..ea9b617d --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb @@ -0,0 +1,105 @@ +class <%= controller_class_name %>Controller < ApplicationController + <%- if defined?(Resourceful::Maker) -%> + make_resourceful do + actions :all + + # Let's get the most use from form_for and share a single form here! + response_for :new, :edit do + render :template => "<%= plural_name %>/form" + end + + response_for :create_fails, :update_fails do + flash[:error] = "There was a problem!" + render :template => "<%= plural_name %>/form" + end + end + <%- else -%> + # GET /<%= table_name %> + # GET /<%= table_name %>.xml + def index + @<%= table_name %> = <%= class_name %>.find(:all) + + respond_to do |format| + format.html # index.html.erb + format.xml { render :xml => @<%= table_name %> } + end + end + + # GET /<%= table_name %>/1 + # GET /<%= table_name %>/1.xml + def show + @<%= file_name %> = <%= class_name %>.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.xml { render :xml => @<%= file_name %> } + end + end + + # GET /<%= table_name %>/new + # GET /<%= table_name %>/new.xml + def new + @<%= file_name %> = <%= class_name %>.new + + respond_to do |format| + format.html { render :template => "<%= plural_name %>/form" } + format.xml { render :xml => @<%= file_name %> } + end + end + + # GET /<%= table_name %>/1/edit + def edit + @<%= file_name %> = <%= class_name %>.find(params[:id]) + render :template => "<%= plural_name %>/form" + end + + # POST /<%= table_name %> + # POST /<%= table_name %>.xml + def create + @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>]) + + respond_to do |format| + if @<%= file_name %>.save + flash[:notice] = '<%= class_name %> was successfully created.' + format.html { redirect_to(@<%= file_name %>) } + format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> } + else + flash.now[:error] = '<%= class_name %> could not be created.' + format.html { render :template => "<%= plural_name %>/form" } + format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity } + end + end + end + + # PUT /<%= table_name %>/1 + # PUT /<%= table_name %>/1.xml + def update + @<%= file_name %> = <%= class_name %>.find(params[:id]) + + respond_to do |format| + if @<%= file_name %>.update_attributes(params[:<%= file_name %>]) + flash[:notice] = '<%= class_name %> was successfully updated.' + format.html { redirect_to(@<%= file_name %>) } + format.xml { head :ok } + else + flash.now[:error] = '<%= class_name %> could not be created.' + format.html { render :template => "<%= plural_name %>/form" } + format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity } + end + end + end + + # DELETE /<%= table_name %>/1 + # DELETE /<%= table_name %>/1.xml + def destroy + @<%= file_name %> = <%= class_name %>.find(params[:id]) + @<%= file_name %>.destroy + + respond_to do |format| + flash[:notice] = '<%= class_name %> was successfully deleted.' + format.html { redirect_to(<%= table_name %>_url) } + format.xml { head :ok } + end + end + <%- end -%> +end diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb new file mode 100644 index 00000000..dc6d5599 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb @@ -0,0 +1,116 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= controller_class_name %>Controller do + def valid_attributes(args = {}) + { +<% if attributes.empty? -%> + # Add valid attributes for the your params[:<%= singular_name %>] here! +<% else -%> + <%- attributes.each_with_index do |attribute, index| -%> + <%- case attribute.type -%> + <%- when :string, :text -%> + "<%= attribute.name %>" => "foo"<%= index < attributes.size - 1 ? "," : "" %> + <%- when :integer, :float, :decimal -%> + "<%= attribute.name %>" => 815<%= index < attributes.size - 1 ? "," : "" %> + <%- when :boolean -%> + "<%= attribute.name %>" => false<%= index < attributes.size - 1 ? "," : "" %> + <%- when :date, :datetime, :time, :timestamp -%> + "<%= attribute.name %>" => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> + <%- else -%> + "<%= attribute.name %>" => nil<%= index < attributes.size - 1 ? "," : "" %> # Could not determine valid attribute + <%- end -%> + <%- end -%> +<% end -%> + }.merge(args) + end + + describe "GET :index" do + before(:each) do + @<%= plural_name %> = stub_index(<%= class_name %>) + end + + it_should_find_and_assign :<%= plural_name %> + it_should_render_template "index" + end + + describe "GET :new" do + before(:each) do + @<%= singular_name %> = stub_new(<%= class_name %>) + end + + it_should_initialize_and_assign :<%= singular_name %> + it_should_render_template "form" + end + + describe "POST :create" do + describe "when successful" do + before(:each) do + @<%= singular_name %> = stub_create(<%= class_name %>) + end + + it_should_initialize_and_save :<%= singular_name %> + it_should_set_flash :notice + it_should_redirect_to { <%= singular_name %>_url(@<%= singular_name %>) } + end + + describe "when unsuccessful" do + before(:each) do + @<%= singular_name %> = stub_create(<%= class_name %>, :return => :false) + end + + it_should_initialize_and_assign :<%= singular_name %> + it_should_set_flash :error + it_should_render_template "form" + end + end + + describe "GET :show" do + before(:each) do + @<%= singular_name %> = stub_show(<%= class_name %>) + end + + it_should_find_and_assign :<%= singular_name %> + it_should_render_template "show" + end + + describe "GET :edit" do + before(:each) do + @<%= singular_name %> = stub_edit(<%= class_name %>) + end + + it_should_find_and_assign :<%= singular_name %> + it_should_render_template "form" + end + + describe "PUT :update" do + describe "when successful" do + before(:each) do + @<%= singular_name %> = stub_update(<%= class_name %>) + end + + it_should_find_and_update :<%= singular_name %> + it_should_set_flash :notice + it_should_redirect_to { <%= singular_name %>_url(@<%= singular_name %>) } + end + + describe "when unsuccessful" do + before(:each) do + @<%= singular_name %> = stub_update(<%= class_name %>, :return => :false) + end + + it_should_find_and_assign :<%= singular_name %> + it_should_set_flash :error + it_should_render_template "form" + end + end + + describe "DELETE :destroy" do + before(:each) do + @<%= singular_name %> = stub_destroy(<%= class_name %>) + end + + it_should_find_and_destroy :<%= singular_name %> + it_should_set_flash :notice + it_should_redirect_to { <%= plural_name %>_url } + end +end diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb new file mode 100644 index 00000000..ac30dc1b --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb @@ -0,0 +1,25 @@ +

<%= singular_name %>.new_record? ? "New" : "Edit" %> <%= model_name %>

+<%% form_for(@<%= singular_name %>) do |f| %> +
+ <%%= f.error_messages %> +
+ <%- if attributes.blank? -%> +

Add your form elements here, please!

+ <%- else -%> + <%- attributes.each do |attribute| -%> +

+ <%%= f.label :<%= attribute.name %> %>
+ <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %> +

+ <%- end -%> + <%- end -%> +
+ <%%= submit_tag "Save" %> + +
+<%% end -%> \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml new file mode 100644 index 00000000..d97eabb9 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml @@ -0,0 +1,18 @@ +%h1== #{@<%= singular_name %>.new_record? ? "New" : "Edit"} #{<%= model_name %>} +- form_for @<%= singular_name %> do |f| + #form_errors= f.error_messages +<% if attributes.blank? -%> + %p Add your form elements here, please! +<% else -%> + <%- attributes.each do |attribute| -%> + %p + = f.label :<%= attribute.name %> + = f.<%= attribute.field_type %> :<%= attribute.name %> + <%- end -%> +<% end -%> + #commands + = submit_tag "Save" +#navigation_commands + - unless @<%= singular_name %>.new_record? + = button_to "Show", <%= singular_name %>_path(@<%= singular_name %>), :method => "get", :title => "Show <%= singular_name %>. Unsaved changes will be lost." + = button_to "Back to List", <%= plural_name %>_path, :class => "cancel", :method => "get", :title => "Return to <%= singular_name %> list without saving changes" \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb new file mode 100644 index 00000000..acdf2d01 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' + +describe "<%= File.join(controller_class_path, controller_singular_name) %>/form.html.<%= template_language %>" do + before(:each) do + @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { +<% if attributes.blank? -%> + # Add your stub attributes and return values here like: + # :name => "Foo", :created_at => 1.week.ago, :updated_at => nil +<% else -%> + <%- attributes.each_with_index do |attribute, index| -%> + <%- case attribute.type -%> + <%- when :string, :text -%> + :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> + <%- when :integer, :float, :decimal -%> + :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> + <%- when :boolean -%> + :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> + <%- when :date, :datetime, :time, :timestamp -%> + :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> + <%- else -%> + :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> # Could not determine valid attribute + <%- end -%> + <%- end -%> +<% end -%> + }) + end + + it_should_have_form_for :<%= singular_name %> +<% if attributes.blank? -%> + # Add specs for editing attributes here, please! Like this: + # + # it_should_allow_editing :<%= singular_name %>, :foo +<% else -%> + <%- attributes.each do |attribute| -%> + it_should_allow_editing :<%= singular_name %>, :<%= attribute.name %> + <%- end -%> +<% end -%> + + it_should_link_to_show :<%= singular_name %> + it_should_link_to { <%= plural_name %>_path } +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb new file mode 100644 index 00000000..9bd821b1 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb @@ -0,0 +1,2 @@ +module <%= controller_class_name %>Helper +end diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb new file mode 100644 index 00000000..6a34ca2a --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb @@ -0,0 +1,5 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../spec_helper' + +describe <%= controller_class_name %>Helper do + # Add your specs here or remove this file completely, please! +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb new file mode 100644 index 00000000..318f94e3 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb @@ -0,0 +1,31 @@ +

<%= model_name %> List

+ + <%%- if @<%= plural_name %>.empty? -%> + + + + + + <%%- else -%> + + + <%- if attributes.blank? -%> + + <%- else -%> + <%- attributes.each do |attribute| -%> + + <%- end -%> + <%- end -%> + + + + + + + <%%= render :partial => @<%= plural_name %> %> + + <%%- end -%> +
There are no <%= plural_name.humanize.downcase %>
<%= attribute.name.titleize %>
+
+ <%%= button_to "New <%= singular_name.titleize %>", new_<%= singular_name %>_path, :method => "get" %> +
\ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml new file mode 100644 index 00000000..b0c78b28 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml @@ -0,0 +1,23 @@ +%h1 <%= model_name %> List +%table + - if @<%= plural_name %>.empty? + %tbody + %tr.empty + %td== There are no <%= plural_name.humanize.downcase %> + - else + %thead + %tr +<% if attributes.blank? -%> + %th= # Generic display column +<% else -%> + <%- attributes.each do |attribute| -%> + %th <%= attribute.name.titleize %> + <%- end -%> +<% end -%> + %th.show= # 'Show' link column + %th.edit= # 'Edit' link column + %th.delete= # 'Delete' link column + %tbody + = render :partial => @<%= plural_name %> +#commands + = button_to "New <%= singular_name.titleize %>", new_<%= singular_name %>_path, :method => "get" \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb new file mode 100644 index 00000000..1b3e09d0 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' + +describe "<%= File.join(controller_class_path, controller_singular_name) %>/index.html.<%= template_language %>" do + before(:each) do + @<%= plural_name %> = mock_and_assign_collection(<%= model_name %>) + template.stub_render :partial => @<%= plural_name %> + end + + it "should render :partial => @<%= plural_name %>" do + template.expect_render :partial => @<%= plural_name %> + do_render + end + + it_should_link_to_new :<%= singular_name %> +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb new file mode 100644 index 00000000..ecdca836 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb @@ -0,0 +1,12 @@ +"> +<% if attributes.blank? -%> + <%= model_name %> #<%%= <%= singular_name %>.id %> +<% else -%> + <%- attributes.each do |attribute| -%> + <%%=h <%= singular_name %>.<%= attribute.name %> %> + <%- end %> +<% end -%> + <%%= button_to "Show", <%= singular_name %>, :method => "get" %> + <%%= button_to "Edit", edit_<%= singular_name %>_path(<%= singular_name %>), :method => "get" %> + <%%= button_to "Delete", <%= singular_name %>, :method => "delete" %> + \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml new file mode 100644 index 00000000..08b3b383 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml @@ -0,0 +1,11 @@ +%tr{:class => cycle("odd", "even")} +<% if attributes.blank? -%> + %td== <%= model_name %> #{<%= singular_name %>.id} +<% else -%> + <%- attributes.each do |attribute| -%> + %td=h <%= singular_name %>.<%= attribute.name %> + <%- end -%> +<% end -%> + %td.show= button_to "Show", <%= singular_name %>_path(<%= singular_name %>), :method => "get" + %td.edit= button_to "Edit", edit_<%= singular_name %>_path(<%= singular_name %>), :method => "get" + %td.delete= button_to "Delete", <%= singular_name %>, :method => "delete" \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb new file mode 100644 index 00000000..3f112e5e --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' + +describe "<%= File.join(controller_class_path, controller_singular_name) %>/_<%= singular_name %>.html.<%= template_language %>" do + before(:each) do + @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { +<% if attributes.blank? -%> + # Add your stub attributes and return values here like: + # :name => "Foo", :created_at => 1.week.ago, :updated_at => nil +<% else -%> + <%- attributes.each_with_index do |attribute, index| -%> + <%- case attribute.type -%> + <%- when :string, :text -%> + :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> + <%- when :integer, :float, :decimal -%> + :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> + <%- when :boolean -%> + :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> + <%- when :date, :datetime, :time, :timestamp -%> + :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> + <%- else -%> + :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> + <%- end -%> + <%- end -%> +<% end -%> + }) + template.stub!(:<%= singular_name %>).and_return(@<%= singular_name %>) + end + + it_should_link_to_show :<%= singular_name %> + it_should_link_to_edit :<%= singular_name %> + it_should_link_to_delete :<%= singular_name %> +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb new file mode 100644 index 00000000..2e4c29c8 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb @@ -0,0 +1,14 @@ +class <%= migration_name %> < ActiveRecord::Migration + def self.up + create_table :<%= table_name %>, :force => true do |t| +<% attributes.each do |attribute| -%> + t.column :<%= attribute.name %>, :<%= attribute.type %> +<% end -%> + t.timestamps + end + end + + def self.down + drop_table :<%= table_name %> + end +end diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb new file mode 100644 index 00000000..202f8b30 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb @@ -0,0 +1,2 @@ +class <%= class_name %> < ActiveRecord::Base +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb new file mode 100644 index 00000000..119349fc --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper' + +describe <%= class_name %> do + def valid_attributes(args = {}) + { + # Add valid attributes for building your model instances here! + }.merge(args) + end + + before(:each) do + @<%= singular_name %> = <%= class_name %>.new + end + + after(:each) do + @<%= singular_name %>.destroy unless @<%= singular_name %>.new_record? + end + + # Add your model specs here, please! + # And don't forget about the association matchers built-in to skinny_spec like: + # + # it_should_have_many :foos + # it_should_validate_presence_of :bar + # + # Check out the docs for more information. +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb new file mode 100644 index 00000000..5db36d56 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb @@ -0,0 +1,15 @@ +

Show <%= model_name %>

+<% if attributes.blank? -%> +

Add your customized markup here, please!

+<% else -%> + <%- attributes.each do |attribute| -%> +

+ + <%%=h @<%= singular_name %>.<%= attribute.name %> %> +

+ <%- end -%> +<% end -%> +
+ <%%= button_to "Edit", edit_<%= singular_name %>_path(@<%= singular_name %>), :method => "get" %> + <%%= button_to "Back to List", <%= plural_name %>_path, :method => "get" %> +
diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml new file mode 100644 index 00000000..d8afe80a --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml @@ -0,0 +1,13 @@ +%h1== Show #{<%= model_name %>} +<% if attributes.blank? -%> +%p Add your customized markup here, please! +<% else -%> + <%- attributes.each do |attribute| -%> +%p + %label <%= attribute.name.titleize %>: + =h @<%= singular_name %>.<%= attribute.name %> + <%- end -%> +<% end -%> +#commands + = button_to "Edit", edit_<%= singular_name %>_path(@<%= singular_name %>), :method => "get" + = button_to "Back to List", <%= plural_name %>_path, :method => "get" \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb new file mode 100644 index 00000000..1c6c7aa8 --- /dev/null +++ b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' + +describe "<%= File.join(controller_class_path, controller_singular_name) %>/show.html.<%= template_language %>" do + before(:each) do +<% if attributes.blank? -%> + @<%= singular_name %> = mock_and_assign(<%= model_name %>) +<% else -%> + @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { + <%- attributes.each_with_index do |attribute, index| -%> + <%- case attribute.type -%> + <%- when :string, :text -%> + :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> + <%- when :integer, :float, :decimal -%> + :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> + <%- when :boolean -%> + :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> + <%- when :date, :datetime, :time, :timestamp -%> + :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> + <%- else -%> + :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> + <%- end -%> + <%- end -%> + }) +<% end -%> + end + + # Add your specs here, please! But remember not to make them brittle + # by specing specing specific HTML elements and classes. + + it_should_link_to_edit :<%= singular_name %> + it_should_link_to { <%= plural_name %>_path } +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/init.rb b/vendor/plugins/skinny_spec/init.rb new file mode 100644 index 00000000..4906d276 --- /dev/null +++ b/vendor/plugins/skinny_spec/init.rb @@ -0,0 +1,3 @@ +if RAILS_ENV == "test" + require "skinny_spec" +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb new file mode 100644 index 00000000..2506accb --- /dev/null +++ b/vendor/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb @@ -0,0 +1,46 @@ +module LuckySneaks + # These methods are mostly just called internally by various other spec helper + # methods but you're welcome to use them as needed in your own specs. + module CommonSpecHelpers + # Returns class for the specified name. Example: + # + # class_for("foo") # => Foo + def class_for(name) + name.to_s.constantize + rescue NameError + name.to_s.classify.constantize + # Let any other error rise! + end + + # Returns instance variable for the specified name. Example: + # + # instance_for("foo") # => @foo + def instance_for(name) + instance_variable_get("@#{name.to_s.underscore}") + end + + # Wraps a matcher that checks if the receiver contains an A element (link) + # whose href attribute is set to the specified path. + def have_link_to(path) + have_tag("a[href='#{path}']") + end + + # Returns dummy value for specified attribute based on the datatype expected for that + # attribute. + def dummy_value_for(instance, attribute) + if datatype = instance.column_for_attribute(attribute) + actual = instance.send(attribute) + case datatype.type + when :string, :text + actual == "foo" ? "bar" : "food" + when :integer, :float, :decimal + actual == 108 ? 815 : 108 + when :boolean + actual ? false : true + when :date, :datetime, :time, :timestamp + actual == 1.week.ago ? 2.years.ago : 1.week.ago + end + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb new file mode 100644 index 00000000..a7cd5b94 --- /dev/null +++ b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb @@ -0,0 +1,67 @@ +module LuckySneaks + module ControllerRequestHelpers # :nodoc: + def self.included(base) + base.extend ExampleGroupMethods + end + + private + def define_implicit_request(method) + @controller_method = method + @implicit_request = case method + when :index, :new, :show, :edit + proc { get method, params } + when :create + proc { post :create, params } + when :update + proc { put :update, params } + when :destroy + proc { put :destroy, params } + end + end + + def eval_request + instance_eval &self.class.instance_variable_get("@the_request") + rescue ArgumentError # missing block + try_shared_request_definition + end + alias do_request eval_request + + def try_shared_request_definition + shared_request + rescue NameError + if @implicit_request + try_implicit_request + else + error_message = "Could not determine request definition for 'describe' context. " + error_message << "Please use define_request or define a shared_request." + raise ArgumentError, error_message + end + end + + def try_implicit_request + @implicit_request.call + end + + def get_response(&block) + eval_request + block.call(response) if block_given? + response + end + + module ExampleGroupMethods + # Defines a request at the example group ("describe") level to be evaluated in the examples. Example: + # + # define_request { get :index, params } + # + # Note: The following methods all define implicit requests: stub_index, stub_new, + # stub_create, stub_show, stub_edit, stub_update, and + # stub_destroy. Using them in your before blocks will allow you to forego + # defining explicit requests using define_request. See + # LuckySneaks::ControllerStubHelpers for information on these methods. + def define_request(&block) + raise ArgumentError, "Must provide a block to define a request!" unless block_given? + @the_request = block + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb new file mode 100644 index 00000000..43210f93 --- /dev/null +++ b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb @@ -0,0 +1,435 @@ +$:.unshift File.join(File.dirname(__FILE__), "..") +require "skinny_spec" + +module LuckySneaks + module ControllerSpecHelpers # :nodoc: + include LuckySneaks::CommonSpecHelpers + include LuckySneaks::ControllerRequestHelpers + include LuckySneaks::ControllerStubHelpers + + def self.included(base) + base.extend ExampleGroupMethods + base.extend ControllerRequestHelpers::ExampleGroupMethods + end + + # Evaluates the specified block for each of the RESTful controller methods. + # This is useful to spec that all controller methods redirect when no user is + # logged in. + def with_default_restful_actions(params = {}, &block) + { + :get => :index, + :get => :new, + :post => :create + }.each do |method_id, message| + self.send method_id, message, params + block.call + end + { + :get => :edit, + :put => :update, + :delete => :destroy + }.each do |method_id, message| + if params[:before] + params.delete(:before).call + end + # Presuming any id will do + self.send method_id, message, params.merge(:id => 1) + block.call + end + end + + private + def create_ar_class_expectation(name, method, argument = nil, options = {}) + args = [] + if [:create, :update].include?(@controller_method) + args << (argument.nil? ? valid_attributes : argument) + else + args << argument unless argument.nil? + end + args << options unless options.empty? + if args.empty? + return_value = class_for(name).send(method) + class_for(name).should_receive(method).and_return(return_value) + else + return_value = class_for(name).send(method, *args) + class_for(name).should_receive(method).with(*args).and_return(return_value) + end + end + + def create_positive_ar_instance_expectation(name, method, *args) + instance = instance_for(name) + if args.empty? + return_value = instance.send(method) + instance.should_receive(method).and_return(true) + else + return_value = instance.send(method, *args) + instance.should_receive(method).with(*args).and_return(true) + end + end + + # These methods are designed to be used at the example group [read: "describe"] level + # to simplify and DRY up common expectations. + module ExampleGroupMethods + # Creates an expectation that the controller method calls ActiveRecord::Base.find. + # Examples: + # + # it_should_find :foos # => Foo.should_receive(:find).with(:all) + # it_should_find :foos, :all # An explicit version of the above + # it_should_find :foos, :conditions => {:foo => "bar"} # => Foo.should_receive(:find).with(:all, :conditions => {"foo" => "bar"} + # it_should_find :foo # => Foo.should_recieve(:find).with(@foo.id.to_s) + # it_should_find :foo, :params => "id" # => Foo.should_receive(:find).with(params[:id].to_s) + # it_should_find :foo, 2 # => Foo.should_receive(:find).with("2") + # + # Note: All params (key and value) will be strings if they come from a form element and are handled + # internally with this expectation. + def it_should_find(name, *args) + name_string = name.to_s + name_message = if name_string == name_string.singularize + "a #{name}" + else + name + end + it "should find #{name_message}" do + options = args.extract_options! + # Blech! + argument = if param = params[options.delete(:params)] + param.to_s + else + if args.first + args.first + elsif (instance = instance_variable_get("@#{name}")).is_a?(ActiveRecord::Base) + instance.id.to_s + else + :all + end + end + create_ar_class_expectation name, :find, argument, options + eval_request + end + end + + # Creates an expectation that the controller method calls ActiveRecord::Base.new. + # Takes optional params for the initialization arguments. Example + # + # it_should_initialize :foo # => Foo.should_receive(:new) + # it_should_initialize :foo, :params => :bar # => Foo.should_receive(:new).with(params[:bar]) + # it_should_initialize :foo, :bar => "baz" # => Foo.should_receive(:new).with(:bar => "baz") + def it_should_initialize(name, options = {}) + it "should initialize a #{name}" do + create_ar_class_expectation name, :new, params[options.delete(:params)], options + eval_request + end + end + + # Creates an expectation that the controller method calls ActiveRecord::Base#save on the + # named instance. Example: + # + # it_should_save :foo # => @foo.should_receive(:save).and_return(true) + # + # Note: This helper should not be used to spec a failed save call. Use it_should_assign + # instead, to verify that the instance is captured in an instance variable for the inevitable re-rendering + # of the form template. + def it_should_save(name) + it "should save the #{name}" do + create_positive_ar_instance_expectation name, :save + eval_request + end + end + + # Creates an expectation that the controller method calls ActiveRecord::Base#update_attributes + # on the named instance. Takes optional argument for params to specify in the + # expectation. Examples: + # + # it_should_update :foo # => @foo.should_receive(:update_attributes).and_return(true) + # it_should_update :foo, :params => :bar # => @foo.should_receive(:update_attributes).with(params[:bar]).and_return(true) + # + # Note: This helper should not be used to spec a failed update_attributes call. Use + # it_should_assign instead, to verify that the instance is captured in an instance variable + # for the inevitable re-rendering of the form template. + def it_should_update(name, options = {}) + it "should update the #{name}" do + create_positive_ar_instance_expectation name, :update_attributes, params[options[:params]] + eval_request + end + end + + # Creates an expectation that the controller method calls ActiveRecord::Base#destroy on the named + # instance. Example: + # + # it_should_destroy :foo # => @foo.should_receive(:destroy).and_return(true) + # + # Note: This helper should not be used to spec a failed destroy call. Use + # it_should_assign instead, if you need to verify that the instance is captured in an instance + # variable if it is re-rendered somehow. This is probably a really edge use case. + def it_should_destroy(name, options = {}) + it "should delete the #{name}" do + create_positive_ar_instance_expectation name, :destroy + eval_request + end + end + + # Creates expectation[s] that the controller method should assign the specified + # instance variables along with any specified values. Examples: + # + # it_should_assign :foo # => assigns[:foo].should == @foo + # it_should_assign :foo => "bar" # => assigns[:foo].should == "bar" + # it_should_assign :foo => :nil # => assigns[:foo].should be_nil + # it_should_assign :foo => :not_nil # => assigns[:foo].should_not be_nil + # it_should_assign :foo => :undefined # => controller.send(:instance_variables).should_not include("@foo") + # + # Very special thanks to Rick Olsen for the basis of this code. The only reason I even + # redefine it at all is purely an aesthetic choice for specs like "it should foo" + # over ones like "it foos". + def it_should_assign(*names) + names.each do |name| + if name.is_a?(Symbol) + it_should_assign name => name + elsif name.is_a?(Hash) + name.each do |key, value| + it_should_assign_instance_variable key, value + end + end + end + end + + # Wraps the separate expectations it_should_find and it_should_assign + # for simple cases. If you need more control over the parameters of the find, this + # isn't the right helper method and you should write out the two expectations separately. + def it_should_find_and_assign(*names) + names.each do |name| + it_should_find name + it_should_assign name + end + end + + # Wraps the separate expectations it_should_initialize and it_should_assign + # for simple cases. If you need more control over the parameters of the initialization, this + # isn't the right helper method and you should write out the two expectations separately. + # + # Note: This method is used for controller methods like new, where the instance + # is initialized without being saved (this includes failed create requests). + # If you want to spec that the controller method successfully saves the instance, + # please use it_should_initialize_and_save. + def it_should_initialize_and_assign(*names) + names.each do |name| + it_should_initialize name + it_should_assign name + end + end + + # Wraps the separate expectations it_should_initialize and it_should_save + # for simple cases. If you need more control over the parameters of the initialization, this + # isn't the right helper method and you should write out the two expectations separately. + # + # Note: This method is used for controller methods like create, where the instance + # is initialized and successfully saved. If you want to spec that the instance is created + # but not saved, just use it_should_initialize_and_assign. + def it_should_initialize_and_save(*names) + names.each do |name| + it_should_initialize name + it_should_save name + end + end + + # Wraps the separate expectations it_should_find and it_should_update + # for simple cases. If you need more control over the parameters of the find, this + # isn't the right helper method and you should write out the two expectations separately. + # + # Note: This method is used for controller methods like update, where the + # instance is loaded from the database and successfully saved. If you want to spec that the + # instance is found but not saved, just use it_should_find_and_assign. + def it_should_find_and_update(*names) + names.each do |name| + it_should_find name + it_should_update name + end + end + + # Wraps the separate expectations it_should_find and it_should_destroy + # for simple cases. If you need more control over the parameters of the find, this + # isn't the right helper method and you should write out the two expectations separately. + def it_should_find_and_destroy(*names) + names.each do |name| + it_should_find name + it_should_destroy name + end + end + + # Creates an expectation that the specified collection (flash or session) + # contains the specified key and value. To specify that the collection should be set + # to nil, specify the value as :nil instead. + def it_should_set(collection, key, value = nil, &block) + it "should set #{collection}[:#{key}]" do + # Allow flash.now[:foo] to remain in the flash + flash.stub!(:sweep) if collection == :flash + eval_request + if value + if value == :nil + self.send(collection)[key].should be_nil + else + self.send(collection)[key].should == value + end + elsif block_given? + self.send(collection)[key].should == block.call + else + self.send(collection)[key].should_not be_nil + end + end + end + + # Wraps it_should_set :flash. To specify that the collection should be set + # to nil, specify the value as :nil instead. + def it_should_set_flash(name, value = nil, &block) + it_should_set :flash, name, value, &block + end + + # Wraps it_should_set :session. To specify that the collection should be set + # to nil, specify the value as :nil instead. + def it_should_set_session(name, value = nil, &block) + it_should_set :session, name, value, &block + end + + # Wraps the various it_should_render_foo methods: + # it_should_render_template, it_should_render_partial, + # it_should_render_xml, it_should_render_json, + # it_should_render_formatted, and it_should_render_nothing. + def it_should_render(render_method, *args) + send "it_should_render_#{render_method}", *args + end + + # Creates an expectation that the controller method renders the specified template. + # Accepts the following options which create additional expectations. + # + # :content_type:: Creates an expectation that the Content-Type header for the response + # matches the one specified + # :status:: Creates an expectation that the HTTP status for the response + # matches the one specified + def it_should_render_template(name, options = {}) + create_status_expectation options[:status] if options[:status] + it "should render '#{name}' template" do + eval_request + response.should render_template(name) + end + create_content_type_expectation(options[:content_type]) if options[:content_type] + end + + # Creates an expectation that the controller method renders the specified partial. + # Accepts the following options which create additional expectations. + # + # :content_type:: Creates an expectation that the Content-Type header for the response + # matches the one specified + # :status:: Creates an expectation that the HTTP status for the response + # matches the one specified + def it_should_render_partial(name, options = {}) + create_status_expectation options[:status] if options[:status] + it "should render '#{name}' partial" do + controller.expect_render(:partial => name) + eval_request + end + create_content_type_expectation(options[:content_type]) if options[:content_type] + end + + # Creates an expectation that the controller method renders the specified record via to_xml. + # Accepts the following options which create additional expectations. + # + # :content_type:: Creates an expectation that the Content-Type header for the response + # matches the one specified + # :status:: Creates an expectation that the HTTP status for the response + # matches the one specified + def it_should_render_xml(record = nil, options = {}, &block) + it_should_render_formatted :xml, record, options, &block + end + + # Creates an expectation that the controller method renders the specified record via to_json. + # Accepts the following options which create additional expectations. + # + # :content_type:: Creates an expectation that the Content-Type header for the response + # matches the one specified + # :status:: Creates an expectation that the HTTP status for the response + # matches the one specified + def it_should_render_json(record = nil, options = {}, &block) + it_should_render_formatted :json, record, options, &block + end + + # Called internally by it_should_render_xml and it_should_render_json + # but should not really be called much externally unless you have defined your own + # formats with a matching to_foo method on the record. + # + # Which is probably never. + def it_should_render_formatted(format, record = nil, options = {}, &block) + create_status_expectation options[:status] if options[:status] + it "should render #{format.inspect}" do + if record.is_a?(Hash) + options = record + record = nil + end + if record.nil? && !block_given? + raise ArgumentError, "it_should_render must be called with either a record or a block and neither was given." + else + if record + pieces = record.to_s.split(".") + record = instance_variable_get("@#{pieces.shift}") + record = record.send(pieces.shift) until pieces.empty? + end + block ||= proc { record.send("to_#{format}") } + get_response do |response| + response.should have_text(block.call) + end + end + end + create_content_type_expectation(options[:content_type]) if options[:content_type] + end + + # Creates an expectation that the controller method returns a blank page. You'd already + # know when and why to use this so I'm not typing it out. + def it_should_render_nothing(options = {}) + create_status_expectation options[:status] if options[:status] + it "should render :nothing" do + get_response do |response| + response.body.strip.should be_blank + end + end + end + + # Creates an expectation that the controller method redirects to the specified destination. Example: + # + # it_should_redirect_to { foos_url } + # + # Note: This method takes a block to evaluate the route in the example + # context rather than the example group context. + def it_should_redirect_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should redirect to #{(hint || route)}" do + eval_request + response.should redirect_to(instance_eval(&route)) + end + end + + private + def it_should_assign_instance_variable(name, value) + expectation_proc = case value + when :nil + proc { assigns[name].should be_nil } + when :not_nil + proc { assigns[name].should_not be_nil } + when :undefined + proc { controller.send(:instance_variables).should_not include("@{name}") } + when Symbol + if (instance_variable = instance_variable_get("@#{name}")).nil? + proc { assigns[name].should_not be_nil } + else + proc { assigns[name].should == instance_variable } + end + else + proc { assigns[name].should == value } + end + it "should #{value == :nil ? 'not ' : ''}assign @#{name}" do + eval_request + instance_eval &expectation_proc + end + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb new file mode 100644 index 00000000..950c7a17 --- /dev/null +++ b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb @@ -0,0 +1,199 @@ +module LuckySneaks # :nodoc: + # These methods are designed to be used in your example before blocks to accomplish + # a whole lot of functionality with just a tiny bit of effort. The methods which correspond + # to the controller methods perform the most duties as they create the mock_model instances, + # stub out all the necessary methods, and also create implicit requests to DRY up your spec + # file even more. You are encouraged to use these methods to setup the basic calls for your + # resources and only resort to the other methods when mocking and stubbing secondary objects + # and calls. + # + # Both stub_create and stub_update benefit from having a valid_attributes + # method defined at the top level of your example groups, ie the top-most "describe" block + # of the spec file. If you did not generate your specs with skinny_scaffold or + # skinny_resourceful generators, you can simply write a method like the following + # for yourself: + # + # def valid_attributes + # { + # "foo" => "bar", + # "baz" => "quux" + # } + # end + # + # Note this method employs strings as both the key and values to best replicate the way + # they are used in actual controllers where the params will come from a form. + module ControllerStubHelpers + # Stubs out find :all and returns a collection of mock_model + # instances of that class. Accepts the following options: + # + # :format:: Format of the request. Used to only add to_xml and + # to_json when actually needed. + # :size:: Number of instances to return in the result. Default is 3. + # :stub:: Additional methods to stub on the instances + # + # Any additional options will be passed as arguments to the class find. + # You will want to make sure to pass those arguments to the it_should_find spec as well. + def stub_find_all(klass, options = {}) + returning(Array.new(options[:size] || 3){mock_model(klass)}) do |collection| + stub_out klass, options.delete(:stub) + if format = options.delete(:format) + stub_formatted collection, format + params[:format] = format + end + if options.empty? + klass.stub!(:find).with(:all).and_return(collection) + else + klass.stub!(:find).with(:all, options).and_return(collection) + end + end + end + + # Alias for stub_find_all but additionally defines an implicit request get :index. + def stub_index(klass, options = {}) + define_implicit_request :index + stub_find_all klass, options + end + + # Stubs out new method and returns a mock_model instance marked as a new record. + # Accepts the following options: + # + # :format:: Format of the request. Used to only add to_xml and + # to_json when actually needed. + # :stub:: Additional methods to stub on the instances + # + # It also accepts some options used to stub out save with a specified true + # or false but you should be using stub_create in that case. + def stub_initialize(klass, options = {}) + returning mock_model(klass) do |member| + stub_out member, options.delete(:stub) + if format = options[:format] + stub_formatted member, format + params[:format] = format + end + klass.stub!(:new).and_return(member) + if options[:stub_save] + stub_ar_method member, :save, options[:return] + klass.stub!(:new).with(params[options[:params]]).and_return(member) + else + member.stub!(:new_record?).and_return(true) + member.stub!(:id).and_return(nil) + end + end + end + + # Alias for stub_initialize which additionally defines an implicit request get :new. + def stub_new(klass, options = {}) + define_implicit_request :new + stub_initialize klass, options + end + + # Alias for stub_initialize which additionally defines an implicit request post :create. + # + # Note: If stub_create is provided an optional :params hash + # or the method valid_attributes is defined within its scope, + # those params will be added to the example's params object. If neither + # are provided an ArgumentError will be raised. + def stub_create(klass, options = {}) + define_implicit_request :create + if options[:params].nil? + if self.respond_to?(:valid_attributes) + params[klass.name.underscore.to_sym] = valid_attributes + options[:params] = valid_attributes + else + error_message = "Params for creating #{klass} could not be determined. " + error_message << "Please define valid_attributes method in the base 'describe' block " + error_message << "or manually set params in the before block." + raise ArgumentError, error_message + end + end + stub_initialize klass, options.merge(:stub_save => true) + end + + # Stubs out find and returns a single mock_model + # instances of that class. Accepts the following options: + # + # :format:: Format of the request. Used to only add to_xml and + # to_json when actually needed. + # :stub:: Additional methods to stub on the instances + # + # Any additional options will be passed as arguments to find.You will want + # to make sure to pass those arguments to the it_should_find spec as well. + # + # Note: The option :stub_ar is used internally by stub_update + # and stub_destroy. If you need to stub update_attributes or + # destroy you should be using the aforementioned methods instead. + def stub_find_one(klass, options = {}) + returning mock_model(klass) do |member| + stub_out member, options.delete(:stub) + if options[:format] + stub_formatted member, options[:format] + params[:format] = options[:format] + end + if options[:current_object] + params[:id] = member.id + if options[:stub_ar] + stub_ar_method member, options[:stub_ar], options[:return] + end + end + klass.stub!(:find).with(member.id.to_s).and_return(member) + end + end + + # Alias for stub_find_one which additionally defines an implicit request get :show. + def stub_show(klass, options = {}) + define_implicit_request :show + stub_find_one klass, options.merge(:current_object => true) + end + + # Alias for stub_find_one which additionally defines an implicit request get :edit. + def stub_edit(klass, options = {}) + define_implicit_request :edit + stub_find_one klass, options.merge(:current_object => true) + end + + # Alias for stub_find_one which additionally defines an implicit request put :update + # and stubs out the update_attribute method on the instance as well. + # + # Note: If stub_update is provided an optional :params hash + # or the method valid_attributes is defined within its scope, + # those params will be added to the example's params object. If neither + # are provided an ArgumentError will be raised. + def stub_update(klass, options = {}) + define_implicit_request :update + stub_find_one klass, options.merge(:current_object => true, :stub_ar => :update_attributes) + end + + # Alias for stub_find_one which additionally defines an implicit request delete :destroy + # and stubs out the destroy method on the instance as well. + def stub_destroy(klass, options = {}) + define_implicit_request :destroy + stub_find_one klass, options.merge(:current_object => true, :stub_ar => :destroy) + end + + # Stubs to_xml or to_json respectively based on format argument. + def stub_formatted(object, format) + return unless format + object.stub!("to_#{format}").and_return("#{object.class} formatted as #{format}") + end + + private + # Stubs out multiple methods. You shouldn't be calling this yourself and if you do + # you should be able to understand the code yourself, right? + def stub_out(object, stubs = {}) + return if stubs.nil? + stubs.each do |method, value| + if value + object.stub!(method).and_return(value) + else + object.stub!(method) + end + end + end + + # Stubs out ActiveRecord::Base methods like #save, #update_attributes, etc + # that may be called on a found or instantiated mock_model instance. + def stub_ar_method(object, method, return_value) + object.stub!(method).and_return(return_value ? false : true) + end + end +end diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb new file mode 100644 index 00000000..4d65f276 --- /dev/null +++ b/vendor/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb @@ -0,0 +1,326 @@ +$:.unshift File.join(File.dirname(__FILE__), "..") +require "skinny_spec" + +module LuckySneaks + # These methods are designed to be used in your example [read: "it"] blocks + # to make your model specs a little more DRY. You might also be interested + # in checking out the example block [read: "describe"] level versions in of these + # methods which can DRY things up even more: + # LuckySneaks::ModelSpecHelpers::ExampleGroupLevelMethods + # + # Note: The validation matchers are only meant to be used for simple validation checking + # not as a one-size-fits-all solution. + module ModelSpecHelpers + include LuckySneaks::CommonSpecHelpers + + def self.included(base) # :nodoc: + base.extend ExampleGroupLevelMethods + end + + class AssociationMatcher # :nodoc: + def initialize(associated, macro) + @associated = associated + @macro = macro + @options = {} + end + + def matches?(main_model) + unless main_model.respond_to?(:reflect_on_association) + if main_model.class.respond_to?(:reflect_on_association) + main_model = main_model.class + else + @not_model = main_model + return false + end + end + if @association = main_model.reflect_on_association(@associated) + @options.all?{|k, v| @association.options[k] == v || + [@association.options[k]] == v} # Stupid to_a being obsoleted! + end + end + + def failure_message + if @not_model + " expected: #{@not_model} to be a subclass of ActiveRecord::Base class, but was not" + elsif @association + " expected: #{association_with(@options)}\n got: #{association_with(@association.options)}" + else + " expected: #{association_with(@options)}, but the association does not exist" + end + end + + def negative_failure_message + if @association + " expected: #{association_with(@options)}\n got: #{association_with(@association.options)}" + else + " expected: #{association_with(@options)} to not occur but it does" + end + end + + # The following public methods are chainable extensions on the main matcher + # Examples: + # + # Foo.should have_many(:bars).through(:foobars).with_dependent(:destroy) + # Bar.should belong_to(:baz).with_class_name("Unbaz") + def through(through_model) + @options[:through] = through_model + self + end + + def and_includes(included_models) + @options[:include] = included_models + self + end + + def and_extends(*modules) + @options[:extends] = modules + self + end + + def with_counter_cache(counter_cache = false) + if counter_cache + @options[:counter_cache] = counter_cache + end + self + end + + def uniq(*irrelevant_args) + @options[:uniq] = true + self + end + alias and_is_unique uniq + alias with_unique uniq + + def polymorphic(*irrelevant_args) + @options[:polymorphic] = true + self + end + alias and_is_polymorphic polymorphic + alias with_polymorphic polymorphic + + def as(interface) + @options[:as] = interface + end + + # Use this to just specify the options as a hash. + # Note: It will completely override any previously set options + def with_options(options = {}) + options.each{|k, v| @options[k] = v} + self + end + + private + # Takes care of methods like with_dependent(:destroy) + def method_missing(method_id, *args, &block) + method_name = method_id.to_s + if method_name =~ /^with_(.*)/ + @options[$1.to_sym] = args + self + else + super method_id, *args, &block + end + end + + def association_with(options) + option_string = (options.nil? || options.empty?) ? "" : options.inspect + unless option_string.blank? + option_string.sub! /^\{(.*)\}$/, ', \1' + option_string.gsub! /\=\>/, ' => ' + end + "#{@macro} :#{@associated}#{option_string}" + end + end + + # Creates matcher that checks if the receiver has a belongs_to association + # with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def belong_to(model) + AssociationMatcher.new model, :belongs_to + end + + # Creates matcher that checks if the receiver has a have_one association + # with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def have_one(model) + AssociationMatcher.new model, :has_one + end + + # Creates matcher that checks if the receiver has a have_many association + # with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def have_many(models) + AssociationMatcher.new models, :has_many + end + + # Creates matcher that checks if the receiver has a have_and_belong_to_many association + # with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def have_and_belong_to_many(models) + AssociationMatcher.new models, :has_and_belongs_to_many + end + + private + def class_or_instance + @model_spec_class_or_instance ||= class_for(self.class.description_text) || instance + end + + def instance + @model_spec_instance ||= instance_for(self.class.description_text) + end + + # These methods are designed to be used at the example group [read: "describe"] level + # to simplify and DRY up common expectations. Most of these methods are wrappers for + # matchers which can also be used on the example level [read: within an "it" block]. See + # LuckySneaks::ModelSpecHelpers for more information. + module ExampleGroupLevelMethods + # Creates an expectation that the current model being spec'd has a belongs_to + # association with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def it_should_belong_to(model) + it "should belong to a #{model}" do + class_or_instance.should belong_to(model) + end + end + + # Creates an expectation that the current model being spec'd has a have_one + # association with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def it_should_have_one(model) + it "should have one #{model}" do + class_or_instance.should have_one(model) + end + end + + # Creates an expectation that the current model being spec'd has a have_many + # association with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def it_should_have_many(models) + it "should have many #{models}" do + class_or_instance.should have_many(models) + end + end + + # Creates an expectation that the current model being spec'd has a have_and_belong_to_many + # association with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def it_should_have_and_belong_to_many(models) + it "should have and belong to many #{models}" do + class_or_instance.should have_and_belong_to_many(models) + end + end + + # Creates an expectation that the current model being spec'd validates_presence_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + def it_should_validate_presence_of(attribute, message = ActiveRecord::Errors.default_error_messages[:blank]) + it "should not be valid if #{attribute} is blank" do + instance.send "#{attribute}=", nil + instance.errors_on(attribute).should include(message) + end + end + + # Creates an expectation that the current model being spec'd validates_numericality_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + def it_should_validate_numericality_of(attribute, message = ActiveRecord::Errors.default_error_messages[:not_a_number]) + it "should validate #{attribute} is a numeric" do + instance.send "#{attribute}=", "NaN" + instance.errors_on(attribute).should include(message) + end + end + + # Creates an expectation that the current model being spec'd validates_confirmation_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + def it_should_validate_confirmation_of(attribute, message = ActiveRecord::Errors.default_error_messages[:confirmation]) + it "should validate confirmation of #{attribute}" do + dummy_value = dummy_value_for(instance, attribute) || "try a string" + instance.send "#{attribute}=", dummy_value + instance.send "#{attribute}_confirmation=", dummy_value.succ + instance.errors_on(attribute).should include(message) + end + end + + # Creates an expectation that the current model being spec'd validates_uniqueness_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + # + # Note: This method will fail completely if valid_attributes + # does not provide all the attributes needed to create a valid record. + def it_should_validate_uniqueness_of(attribute, message = ActiveRecord::Errors.default_error_messages[:taken]) + it "should validate #{attribute} confirmation" do + previous_instance = class_for(self.class.description_text).create!(valid_attributes) + instance.attributes = valid_attributes + instance.errors_on(attribute).should include(message) + previous_instance.destroy + end + end + + # Creates an expectation that the current model being spec'd accepts the specified values as + # valid for the specified attribute. This is most likely used with validates_format_of + # but there's nothing saying it couldn't be another validation. + def it_should_accept_as_valid(attribute, *values) + values.each do |value| + value_inspect = case value + when String : "'#{value}'" + when NilClass : "nil" + else value + end + it "should accept #{value_inspect} as a valid #{attribute}" do + instance.send "#{attribute}=", value + instance.errors_on(attribute).should == [] + end + end + end + + # Creates an expectation that the current model being spec'd does not accept the specified + # values as valid for the specified attribute. This is most likely used with + # validates_format_of but there's nothing saying it couldn't be another validation. + # Takes an optional argument :message => "some custom error messsage" for + # spec'ing the actual error message. + def it_should_not_accept_as_valid(attribute, *values) + options = values.extract_options! + values.each do |value| + value_inspect = case value + when String : "'#{value}'" + when NilClass : "nil" + else value + end + it "should not accept #{value_inspect} as a valid #{attribute}" do + instance.send "#{attribute}=", value + if options[:message] + instance.errors_on(attribute).should include(options[:message]) + else + instance.should have_at_least(1).errors_on(attribute) + end + end + end + end + # Creates an expectation that the current model being spec'd doesn't allow mass-assignment + # of the specified attribute. + def it_should_not_mass_assign(attribute) + it "should not allow mass-assignment of #{attribute}" do + lambda { + instance.send :attributes=, {attribute => dummy_value_for(instance, attribute)} + }.should_not change(instance, attribute) + end + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb new file mode 100644 index 00000000..eb532554 --- /dev/null +++ b/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb @@ -0,0 +1,460 @@ +$:.unshift File.join(File.dirname(__FILE__), "..") +require "skinny_spec" + +module LuckySneaks + # These methods are designed to be used in your example [read: "it"] blocks + # to make your view specs less brittle and more DRY. You might also be interested + # in checking out the example block [read: "describe"] level versions in of these + # methods which can DRY things up even more: + # LuckySneaks::ViewSpecHelpers::ExampleGroupLevelMethods + module ViewSpecHelpers + include LuckySneaks::CommonSpecHelpers + include ActionController::PolymorphicRoutes + + def self.included(base) # :nodoc: + base.extend ExampleGroupLevelMethods + end + + # Wraps a matcher that checks if the receiver contains a FORM element with + # its action attribute set to the specified path. + def submit_to(path) + have_tag("form[action=#{path}]") + end + + # Wraps a matcher that checks is the receiver contains any of several form elements + # that would return sufficient named parameters to allow editing of the specified + # attribute on the specified instance. Example: + # + # response.should allow_editing(@foo, "bar") + # + # can be satisfied by any of the following HTML elements: + # + # + # + # + # + # + def allow_editing(instance, attribute) + instance_name = instance.class.name.underscore.downcase + if instance.send(attribute).is_a?(Time) + have_tag( + "input[name='#{instance_name}[#{attribute}]'], + select[name=?]", /#{instance_name}\[#{attribute}\(.*\)\]/ + ) + else + have_tag( + "input[type='text'][name='#{instance_name}[#{attribute}]'], + input[type='password'][name='#{instance_name}[#{attribute}]'], + select[name='#{instance_name}[#{attribute}]'], + textarea[name='#{instance_name}[#{attribute}]'], + input[type='checkbox'][name='#{instance_name}[#{attribute}]'], + input[type='checkbox'][name='#{instance_name}[#{attribute.to_s.tableize.singularize}_ids][]']" + ) + end + end + + # Wraps a matcher that checks if the receiver contains an A element (link) + # whose href attribute is set to the specified path or a FORM + # element whose action attribute is set to the specified path. + def have_link_or_button_to(path) + have_tag( + "a[href='#{path}'], + form[action='#{path}'] input, + form[action='#{path}'] button" + ) + end + alias have_link_to have_link_or_button_to + alias have_button_to have_link_or_button_to + + # Wraps have_link_or_button_to new_polymorphic_path for the specified class which + # corresponds with the new method of the controller. + # + # Note: This method may takes a string or symbol representing the model's name + # to send to have_link_or_button_to_show or the model's name itself. + def have_link_or_button_to_new(name) + have_link_or_button_to new_polymorphic_path(name.is_a?(ActiveRecord::Base) ? name : class_for(name)) + end + + # Wraps have_link_or_button_to polymorphic_path(instance) which + # corresponds with the show method of the controller. + def have_link_or_button_to_show(instance) + have_link_or_button_to polymorphic_path(instance) + end + alias have_link_to_show have_link_or_button_to_show + alias have_button_to_show have_link_or_button_to_show + + # Wraps have_link_or_button_to edit_polymorphic_path(instance) which + # corresponds with the edit method of the controller. + def have_link_or_button_to_edit(instance) + have_link_or_button_to edit_polymorphic_path(instance) + end + alias have_link_to_edit have_link_or_button_to_edit + alias have_button_to_edit have_link_or_button_to_edit + + # Wraps a matcher that checks if the receiver contains the HTML created by Rails' + # button_to helper: to wit, a FORM element whose action + # attribute is pointed at the polymorphic_path of the instance + # and contains an INPUT named "_method" with a value of "delete". + def have_button_to_delete(instance) + path = polymorphic_path(instance) + have_tag( + "form[action='#{path}'] input[name='_method'][value='delete'] + input, + form[action='#{path}'] input[name='_method'][value='delete'] + button" + ) + end + + # Creates a mock_model instance and adds it to the assigns collection + # using either the name passed as the first argument or the underscore version + # of its class name. Accepts optional arguments to stub out additional methods + # (and their return values) on the mock_model instance. Example: + # + # mock_and_assign(Foo, :stub => {:bar => "bar"}) + # + # is the same as running assigns[:foo] = mock_model(Foo, :bar => "bar"). + # + # mock_and_assign(Foo, "special_foo", :stub => {:bar => "baz"}) + # + # is the same as running assigns[:special_foo] = mock_model(Foo, :bar => "baz"). + # + # Note: Adding to the assigns collection returns the object added, so this can + # be chained a la @foo = mock_and_assign(Foo). + def mock_and_assign(klass, *args) + options = args.extract_options! + mocked = if options[:stub] + mock_model(klass, options[:stub]) + else + mock_model(klass) + end + yield mocked if block_given? + self.assigns[args.first || "#{klass}".underscore] = mocked + end + + # Creates an array of mock_model instances in the manner of + # mock_and_assign. Accepts option[:size] which sets the size + # of the array (default is 3). + def mock_and_assign_collection(klass, *args) + options = args.dup.extract_options! + return_me = Array.new(options[:size] || 3) do + mocked = if options[:stub] + mock_model(klass, options[:stub]) + else + mock_model(klass) + end + yield mocked if block_given? + mocked + end + self.assigns[args.first || "#{klass}".tableize] = return_me + end + + private + def do_render + if @the_template + render @the_template + elsif File.exists?(File.join(RAILS_ROOT, "app/views", self.class.description_text)) + render self.class.description_text + else + error_message = "Cannot determine template for render. " + error_message << "Please define @the_template in the before block " + error_message << "or name your describe block so that it indicates the correct template." + raise NameError, error_message + end + end + + # These methods are designed to be used at the example group [read: "describe"] level + # to simplify and DRY up common expectations. Most of these methods are wrappers for + # matchers which can also be used on the example level [read: within an "it" block]. See + # LuckySneaks::ViewSpecHelpers for more information. + module ExampleGroupLevelMethods + include LuckySneaks::CommonSpecHelpers + + # Creates an expectation which calls submit_to on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a Proc to evaluate the route not simply a named route + # helper, which would be undefined in the scope of the example block. + def it_should_submit_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should submit to #{(hint || route)}" do + do_render + response.should submit_to(instance_eval(&route)) + end + end + + # Creates an expectation that the template uses Rails' form_for to generate + # the proper form action and method to create or update the specified object. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to create the expectation for form_for + # not an instance variable, which would be nil in the scope of the example block. + # If you use namespacing for your form_for, you'll have to manually write out + # a similar spec. + def it_should_have_form_for(name) + it "should have a form_for(@#{name})" do + template.should_receive(:form_for).with(instance_for(name)) + do_render + end + end + + # Negative version of it_should_have_form_for. See that method for more + # details. + def it_should_not_have_form_for(name) + it "should not have a form_for(@#{name})" do + template.should_not_receive(:form_for).with(instance_for(name)) + do_render + end + end + + # Creates an expectation which calls allow_editing on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to allow_editing + # not an instance variable, which would be nil in the scope of the example block. + def it_should_allow_editing(name, method) + it "should allow editing of @#{name}##{method}" do + do_render + response.should allow_editing(instance_for(name), method) + end + end + + # Negative version of it_should_allow_editing. See that method for more + # details. + def it_should_not_allow_editing(name, method) + it "should not allow editing of @#{name}##{method}" do + do_render + response.should_not allow_editing(instance_for(name), method) + end + end + + # Creates an expectation that the rendered template contains a FORM element + # (INPUT, TEXTAREA, or SELECT) with the specified name. + def it_should_have_form_element_for(name) + it "should have a form element named '#{name}'" do + do_render + response.should have_tag( + "form input[name='#{name}'], + form textarea[name='#{name}'], + form select[name='#{name}']" + ) + end + end + + # Negative version of it_should_have_form_element_for. See that method + # for more details. + def it_should_not_have_form_element_for(name) + it "should not have a form element named '#{name}'" do + do_render + response.should_not have_tag( + "form input[name='#{name}'], + form textarea[name='#{name}'], + form select[name='#{name}']" + ) + end + end + + # Creates an expectation which calls have_link_or_button_to on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a block to evaluate the route in the example context + # instead of the example group context. + def it_should_link_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should have a link/button to #{(hint || route)}" do + do_render + response.should have_link_or_button_to(instance_eval(&route)) + end + end + alias it_should_have_link_to it_should_link_to + alias it_should_have_button_to it_should_link_to + alias it_should_have_button_or_link_to it_should_link_to + + # Negative version of it_should_link_to. See that method + # for more details. + def it_should_not_link_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should have a link/button to #{(hint || route)}" do + do_render + response.should_not have_link_or_button_to(instance_eval(&route)) + end + end + alias it_should_not_have_link_to it_should_not_link_to + alias it_should_not_have_button_to it_should_not_link_to + alias it_should_not_have_button_or_link_to it_should_not_link_to + + # Creates an expectation which calls have_link_or_button_to_new on the response + # from rendering the template. See that method for more details. + # + # Note: This method may takes a string or symbol representing the model's name + # to send to have_link_or_button_to_show or the model's name itself. + def it_should_link_to_new(name) + it "should have a link/button to create a new #{name}" do + do_render + response.should have_link_or_button_to_new(name) + end + end + alias it_should_have_link_to_new it_should_link_to_new + alias it_should_have_button_to_new it_should_link_to_new + alias it_should_have_button_or_link_to_new it_should_link_to_new + + # Negative version of it_should_link_to_show. See that method + # for more details. + def it_should_not_link_to_new(name) + it "should have a link/button to create a new #{name}" do + do_render + response.should_not have_link_or_button_to_new(name) + end + end + alias it_should_not_have_link_to_new it_should_not_link_to_new + alias it_should_not_have_button_to_new it_should_not_link_to_new + alias it_should_not_have_button_or_link_to_new it_should_not_link_to_new + + # Creates an expectation which calls have_link_or_button_to_show on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to have_link_or_button_to_show + # not an instance variable, which would be nil in the scope of the example block. + def it_should_link_to_show(name) + it "should have a link/button to show @#{name}" do + do_render + response.should have_link_or_button_to_show(instance_for(name)) + end + end + alias it_should_have_link_to_show it_should_link_to_show + alias it_should_have_button_to_show it_should_link_to_show + alias it_should_have_button_or_link_to_show it_should_link_to_show + + # Negative version of it_should_link_to_show. See that method + # for more details. + def it_should_not_link_to_show(name) + it "should have a link/button to show @#{name}" do + do_render + response.should_not have_link_or_button_to_show(instance_for(name)) + end + end + alias it_should_not_have_link_to_show it_should_not_link_to_show + alias it_should_not_have_button_to_show it_should_not_link_to_show + alias it_should_not_have_button_or_link_to_show it_should_not_link_to_show + + # Creates an expectation which calls have_link_or_button_to_show + # for each member of the instance variable matching the specified name + # on the response from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name and not an instance variable, which would be nil + # in the scope of the example block. + def it_should_link_to_show_each(name) + it "should have a link/button to show each member of @#{name}" do + do_render + instance_for(name).each do |member| + response.should have_link_or_button_to_show(member) + end + end + end + alias it_should_have_link_to_show_each it_should_link_to_show_each + alias it_should_have_button_to_show_each it_should_link_to_show_each + alias it_should_have_button_or_link_to_show_each it_should_link_to_show_each + + # Creates an expectation which calls have_link_or_button_to_edit on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to have_link_or_button_to_edit + # not an instance variable, which would be nil in the scope of the example block. + def it_should_link_to_edit(name) + it "should have a link/button to edit @#{name}" do + do_render + response.should have_link_or_button_to_edit(instance_for(name)) + end + end + alias it_should_have_link_to_edit it_should_link_to_edit + alias it_should_have_button_to_edit it_should_link_to_edit + alias it_should_have_button_or_link_to_edit it_should_link_to_edit + + # Negative version of it_should_link_to_edit. See that method + # for more details. + def it_should_not_link_to_edit(name) + it "should have a link/button to edit @#{name}" do + do_render + response.should_not have_link_or_button_to_edit(instance_for(name)) + end + end + alias it_should_not_have_link_to_edit it_should_not_link_to_edit + alias it_should_not_have_button_to_edit it_should_not_link_to_edit + alias it_should_not_have_button_or_link_to_edit it_should_not_link_to_edit + + + # Creates an expectation which calls have_link_or_button_to_edit + # for each member of the instance variable matching the specified name + # on the response from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name and not an instance variable, which would be nil + # in the scope of the example block. + def it_should_link_to_edit_each(name) + it "should have a link/button to edit each member of @#{name}" do + do_render + instance_for(name).each do |member| + response.should have_link_or_button_to_edit(member) + end + end + end + alias it_should_have_link_to_edit_each it_should_link_to_edit_each + alias it_should_have_button_to_edit_each it_should_link_to_edit_each + alias it_should_have_button_or_link_to_edit_each it_should_link_to_edit_each + + # Creates an expectation which calls have_link_or_button_to_delete on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to have_link_or_button_to_delete + # not an instance variable, which would be nil in the scope of the example block. + def it_should_link_to_delete(name) + it "should have a link/button to delete @#{name}" do + do_render + response.should have_button_to_delete(instance_for(name)) + end + end + alias it_should_have_link_to_delete it_should_link_to_delete + alias it_should_have_button_to_delete it_should_link_to_delete + alias it_should_have_button_or_link_to_delete it_should_link_to_delete + + # Negative version of it_should_link_to_delete. See that method + # for more details. + def it_should_not_link_to_delete(name) + it "should not have a link/button to delete @#{name}" do + do_render + response.should_not have_button_to_delete(instance_for(name)) + end + end + alias it_should_not_have_link_to_delete it_should_not_link_to_delete + alias it_should_not_have_button_to_delete it_should_not_link_to_delete + alias it_should_not_have_button_or_link_to_delete it_should_not_link_to_delete + + # Creates an expectation which calls have_link_or_button_to_delete + # for each member of the instance variable matching the specified name + # on the response from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name and not an instance variable, which would be nil + # in the scope of the example block. + def it_should_link_to_delete_each(name) + it "should have a link/button to delete each member of @#{name}" do + do_render + instance_for(name).each do |member| + response.should have_button_to_delete(member) + end + end + end + alias it_should_have_link_to_delete_each it_should_link_to_delete_each + alias it_should_have_button_to_delete_each it_should_link_to_delete_each + alias it_should_have_button_or_link_to_delete_each it_should_link_to_delete_each + end + end +end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/skinny_spec.rb b/vendor/plugins/skinny_spec/lib/skinny_spec.rb new file mode 100644 index 00000000..c7883884 --- /dev/null +++ b/vendor/plugins/skinny_spec/lib/skinny_spec.rb @@ -0,0 +1,26 @@ +# Let's make sure everyone else is loaded +require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment") +require 'spec' +require 'spec/rails' +begin + require 'ruby2ruby' +rescue + puts "-----" + puts "Attention: skinny_spec requires ruby2ruby for nicer route descriptions" + puts "It is highly recommended that you install it: sudo gem install ruby2ruby" + puts "-----" +end + +# Let's load our family now +require "lucky_sneaks/common_spec_helpers" +require "lucky_sneaks/controller_request_helpers" +require "lucky_sneaks/controller_spec_helpers" +require "lucky_sneaks/controller_stub_helpers" +require "lucky_sneaks/model_spec_helpers" +require "lucky_sneaks/view_spec_helpers" + +# Let's all come together +Spec::Rails::Example::ViewExampleGroup.send :include, LuckySneaks::ViewSpecHelpers +Spec::Rails::Example::HelperExampleGroup.send :include, LuckySneaks::CommonSpecHelpers +Spec::Rails::Example::ControllerExampleGroup.send :include, LuckySneaks::ControllerSpecHelpers +Spec::Rails::Example::ModelExampleGroup.send :include, LuckySneaks::ModelSpecHelpers \ No newline at end of file