hardbap-coulda 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/LICENSE +21 -0
  2. data/README.markdown +128 -0
  3. data/Rakefile +27 -0
  4. data/TODO +3 -0
  5. data/VERSION.yml +4 -0
  6. data/generators/coulda_model/USAGE +27 -0
  7. data/generators/coulda_model/coulda_model_generator.rb +65 -0
  8. data/generators/coulda_model/templates/factory.rb +5 -0
  9. data/generators/coulda_model/templates/migration.rb +23 -0
  10. data/generators/coulda_model/templates/model.rb +5 -0
  11. data/generators/coulda_model/templates/unit_test.rb +12 -0
  12. data/generators/coulda_scaffold/USAGE +25 -0
  13. data/generators/coulda_scaffold/coulda_scaffold_generator.rb +107 -0
  14. data/generators/coulda_scaffold/templates/controller.rb +72 -0
  15. data/generators/coulda_scaffold/templates/functional_test/shoulda_controller.rb +67 -0
  16. data/generators/coulda_scaffold/templates/helper.rb +2 -0
  17. data/generators/coulda_scaffold/templates/helper_test.rb +5 -0
  18. data/generators/coulda_scaffold/templates/view/_form.html.erb +8 -0
  19. data/generators/coulda_scaffold/templates/view/edit.html.erb +12 -0
  20. data/generators/coulda_scaffold/templates/view/index.html.erb +22 -0
  21. data/generators/coulda_scaffold/templates/view/new.html.erb +8 -0
  22. data/generators/coulda_scaffold/templates/view/show.html.erb +12 -0
  23. data/lib/coulda.rb +0 -0
  24. data/test/fixtures/about_yml_plugins/bad_about_yml/about.yml +1 -0
  25. data/test/fixtures/about_yml_plugins/bad_about_yml/init.rb +1 -0
  26. data/test/fixtures/about_yml_plugins/plugin_without_about_yml/init.rb +1 -0
  27. data/test/fixtures/eager/zoo.rb +3 -0
  28. data/test/fixtures/eager/zoo/reptile_house.rb +2 -0
  29. data/test/fixtures/environment_with_constant.rb +1 -0
  30. data/test/fixtures/lib/generators/missing_class/missing_class_generator.rb +0 -0
  31. data/test/fixtures/lib/generators/working/working_generator.rb +2 -0
  32. data/test/fixtures/plugins/alternate/a/generators/a_generator/a_generator.rb +4 -0
  33. data/test/fixtures/plugins/default/gemlike/init.rb +1 -0
  34. data/test/fixtures/plugins/default/gemlike/lib/gemlike.rb +2 -0
  35. data/test/fixtures/plugins/default/gemlike/rails/init.rb +7 -0
  36. data/test/fixtures/plugins/default/plugin_with_no_lib_dir/init.rb +0 -0
  37. data/test/fixtures/plugins/default/stubby/about.yml +2 -0
  38. data/test/fixtures/plugins/default/stubby/generators/stubby_generator/stubby_generator.rb +4 -0
  39. data/test/fixtures/plugins/default/stubby/init.rb +7 -0
  40. data/test/fixtures/plugins/default/stubby/lib/stubby_mixin.rb +2 -0
  41. data/test/fixtures/tmp/test.log +1 -0
  42. data/test/rails_generators/coulda_model_generator_test.rb +39 -0
  43. data/test/shoulda_macros/generator_macros.rb +36 -0
  44. data/test/stolen_from_railties.rb +288 -0
  45. data/test/test_helper.rb +41 -0
  46. metadata +140 -0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2008 Mike Breen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,128 @@
1
+ # Coulda generator
2
+
3
+ Inspired by [technicalpickles'](http://technicalpickles.com/) [shoulda\_generator](http://github.com/technicalpickles/shoulda_generator) (okay blatantly ripped off from ;)
4
+
5
+ What you'll need:
6
+
7
+ * [shoulda](http://github.com/thoughtbot/shoulda)
8
+ * [factory\_girl](http://github.com/thoughtbot/factory_girl)
9
+
10
+ ## What it does
11
+
12
+ ### coulda\_model
13
+
14
+ * a new model
15
+ * a migration (skip using --skip-migration)
16
+ * a factory defined with [factory\_girl](http://github.com/thoughtbot/factory_girl) (skip using --skip-factory)
17
+ * a [shoulda](http://github.com/thoughtbot/shoulda) unit test with some tests
18
+
19
+
20
+ ### coulda\_scaffold
21
+
22
+ * a coulda\_model
23
+ * a RESTful controller
24
+ * a helper
25
+ * ERB templates
26
+ * a [shoulda](http://github.com/thoughtbot/shoulda) functional test using a [factory\_girl](http://github.com/thoughtbot/factory_girl) factory
27
+ * a helper test in test/unit/helper
28
+
29
+
30
+ ## Example usage
31
+
32
+ Use these just like the standard Rails generators.
33
+
34
+ $ script/generate coulda_model post title:string body:text published:boolean
35
+ $ script/generate coulda_scaffold post title:string body:text published:boolean
36
+
37
+
38
+ ## Other stuff
39
+
40
+ ### belongs\_to
41
+
42
+ Using "belongs\_to" as the field type provides some extra goodness.
43
+
44
+ * "add\_index" in the migration
45
+ * "belongs\_to" in the model
46
+ * "should\_belong\_to" in unit test
47
+ * association in the factory
48
+
49
+ ### example
50
+
51
+ $ script/generate coulda_model post title:string body:text user:belongs_to
52
+
53
+ will give you this migration:
54
+
55
+ class CreatePosts < ActiveRecord::Migration
56
+ def self.up
57
+ create_table :posts do |t|
58
+ t.string :title
59
+ t.text :body
60
+ t.belongs_to :user
61
+
62
+ t.timestamps
63
+ end
64
+
65
+ add_index :posts, :user_id
66
+ end
67
+
68
+ def self.down
69
+ remove_index :posts, :user_id
70
+ drop_table :posts
71
+ end
72
+ end
73
+
74
+ for this model:
75
+
76
+ class Post < ActiveRecord::Base
77
+ belongs_to :user
78
+ end
79
+
80
+ with this unit test:
81
+
82
+ require File.dirname(__FILE__) + '/../test_helper'
83
+
84
+ class PostTest < ActiveSupport::TestCase
85
+
86
+ should_have_db_column :title, :type => "string"
87
+ should_have_db_column :body, :type => "text"
88
+
89
+ should_belong_to :user
90
+ should_have_index :user_id
91
+
92
+ end
93
+
94
+ and finally our factory:
95
+
96
+ Factory.define :post do |f|
97
+ f.title 'MyString'
98
+ f.body 'MyString'
99
+ f.user {|f| f.association(:user)}
100
+ end
101
+
102
+ ## Authors
103
+
104
+ Mike Breen and [Dan Croak](http://github.com/dancroak)
105
+
106
+ ## License
107
+
108
+ The MIT License
109
+
110
+ Copyright (c) 2008 Mike Breen
111
+
112
+ Permission is hereby granted, free of charge, to any person obtaining a copy
113
+ of this software and associated documentation files (the "Software"), to deal
114
+ in the Software without restriction, including without limitation the rights
115
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
116
+ copies of the Software, and to permit persons to whom the Software is
117
+ furnished to do so, subject to the following conditions:
118
+
119
+ The above copyright notice and this permission notice shall be included in
120
+ all copies or substantial portions of the Software.
121
+
122
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
123
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
124
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
125
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
126
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
127
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
128
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'lib'
6
+ t.pattern = 'test/**/*_test.rb'
7
+ t.verbose = false
8
+ end
9
+
10
+ desc "Run the test suite"
11
+ task :default => 'test'
12
+
13
+ begin
14
+ require 'rubygems'
15
+ require 'jeweler'
16
+ Jeweler::Tasks.new do |s|
17
+ s.name = "coulda"
18
+ s.summary = "Rails generators that create Shoulda & Factory Girl tests."
19
+ s.email = "hardbap@gmail.com"
20
+ s.homepage = "http://github.com/hardbap/coulda"
21
+ s.description = "Rails generators that create Shoulda & Factory Girl tests."
22
+ s.authors = ["Mike Breen", "Dan Croak"]
23
+ s.files = FileList["[A-Z]*", "{generators,lib,test}/**/*"]
24
+ end
25
+ rescue LoadError
26
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
27
+ end
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ * remove xml in controller? or add default xml builder?
2
+ * use each iterator instead of for loops
3
+ * no table in index view, use something cleaner
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ patch: 0
3
+ major: 0
4
+ minor: 4
@@ -0,0 +1,27 @@
1
+ Description:
2
+ Stubs out a new model. Pass the model name, either CamelCased or
3
+ under_scored, and an optional list of attribute pairs as arguments.
4
+
5
+ Attribute pairs are column_name:sql_type arguments specifying the
6
+ model's attributes. Timestamps are added by default, so you don't have to
7
+ specify them by hand as 'created_at:datetime updated_at:datetime'.
8
+
9
+ You don't have to think up every attribute up front, but it helps to
10
+ sketch out a few so you can start working with the model immediately.
11
+
12
+ This generates a model class in app/models, a unit test in test/unit,
13
+ a factory in test/factories/singular_name_factory.rb, and a migration in
14
+ db/migrate.
15
+
16
+ Examples:
17
+ `./script/generate coulda_model account`
18
+
19
+ creates an Account model, test, factory, and migration:
20
+ Model: app/models/account.rb
21
+ Test: test/unit/account_test.rb
22
+ Factory: test/factories/account_factory.rb
23
+ Migration: db/migrate/XXX_add_accounts.rb
24
+
25
+ `./script/generate coulda_model post title:string body:text published:boolean`
26
+
27
+ creates a Post model with a string title, text body, and published flag.
@@ -0,0 +1,65 @@
1
+ class CouldaModelGenerator < Rails::Generator::NamedBase
2
+
3
+ default_options :skip_timestamps => false, :skip_migration => false, :skip_factory => false
4
+
5
+ def manifest
6
+ record do |m|
7
+ # Check for class naming collisions.
8
+ m.class_collisions class_path, class_name, "#{class_name}Test"
9
+
10
+ # Model, test, and fixture directories.
11
+ m.directory File.join('app/models', class_path)
12
+ m.directory File.join('test/unit', class_path)
13
+ m.directory File.join('test/factories', class_path)
14
+
15
+ # Model class, unit test, and fixtures.
16
+ m.template 'model.rb',
17
+ File.join('app/models', class_path, "#{file_name}.rb")
18
+ m.template 'unit_test.rb',
19
+ File.join('test/unit', class_path, "#{file_name}_test.rb")
20
+
21
+ unless options[:skip_factory]
22
+ m.template 'factory.rb',
23
+ File.join('test/factories', class_path, "#{file_name}_factory.rb")
24
+ end
25
+
26
+ unless options[:skip_migration]
27
+ m.migration_template 'migration.rb', 'db/migrate', :assigns => {
28
+ :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
29
+ }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
30
+ end
31
+ end
32
+ end
33
+
34
+ def factory_line(attribute)
35
+ line = "factory.#{attribute.name} "
36
+ line << (if attribute.reference?
37
+ then "{ |#{attribute.name}| #{attribute.name}.association(:#{attribute.name}) }"
38
+ else "'#{attribute.default}'"
39
+ end)
40
+ end
41
+
42
+ protected
43
+
44
+ def banner
45
+ "Usage: #{$0} #{spec.name} ModelName [field:type, field:type]"
46
+ end
47
+
48
+ def add_options!(opt)
49
+ opt.separator ''
50
+ opt.separator 'Options:'
51
+ opt.on("--skip-timestamps",
52
+ "Don't add timestamps to the migration file for this model") { |option|
53
+ options[:skip_timestamps] = option
54
+ }
55
+ opt.on("--skip-migration",
56
+ "Don't generate a migration file for this model") { |option|
57
+ options[:skip_migration] = option
58
+ }
59
+ opt.on("--skip-factory",
60
+ "Don't generation a fixture file for this model") { |option|
61
+ options[:skip_factory] = option
62
+ }
63
+ end
64
+
65
+ end
@@ -0,0 +1,5 @@
1
+ Factory.define :<%= file_name %> do |factory|
2
+ <% for attribute in attributes -%>
3
+ <%= factory_line(attribute) %>
4
+ <% end -%>
5
+ end
@@ -0,0 +1,23 @@
1
+ class <%= migration_name %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= table_name %> do |t|
4
+ <% for attribute in attributes -%>
5
+ t.<%= attribute.type %> :<%= attribute.name %>
6
+ <% end -%>
7
+ <% unless options[:skip_timestamps] %>
8
+ t.timestamps
9
+ <% end -%>
10
+ end
11
+
12
+ <% attributes.select(&:reference?).each do |attribute| -%>
13
+ add_index :<%= table_name %>, :<%= attribute.name %>_id
14
+ <% end -%>
15
+ end
16
+
17
+ def self.down
18
+ <% attributes.select(&:reference?).each do |attribute| -%>
19
+ remove_index :<%= table_name %>, :<%= attribute.name %>_id
20
+ <% end %>
21
+ drop_table :<%= table_name %>
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+ <% attributes.select(&:reference?).each do |attribute| -%>
3
+ belongs_to :<%= attribute.name %>
4
+ <% end -%>
5
+ end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class <%= class_name %>Test < ActiveSupport::TestCase
4
+ <% for attribute in attributes -%>
5
+ <% if attribute.reference? %>
6
+ should_belong_to :<%= attribute.name %>
7
+ should_have_index :<%= attribute.name %>_id
8
+ <% else %>
9
+ should_have_db_column :<%= attribute.name %>, :type => "<%= attribute.type %>"
10
+ <% end -%>
11
+ <% end -%>
12
+ end
@@ -0,0 +1,25 @@
1
+ Description:
2
+ Scaffolds an entire resource, from model and migration to controller and
3
+ views, along with a full test suite. The resource is ready to use as a
4
+ starting point for your restful, resource-oriented application.
5
+
6
+ Pass the name of the model, either CamelCased or under_scored, as the first
7
+ argument, and an optional list of attribute pairs.
8
+
9
+ Attribute pairs are column_name:sql_type arguments specifying the
10
+ model's attributes. Timestamps are added by default, so you don't have to
11
+ specify them by hand as 'created_at:datetime updated_at:datetime'.
12
+
13
+ You don't have to think up every attribute up front, but it helps to
14
+ sketch out a few so you can start working with the resource immediately.
15
+
16
+ For example, `coulda_scaffold post title:string body:text published:boolean`
17
+ gives you a model with those three attributes, a controller that handles
18
+ the create/show/update/destroy, forms to create and edit your posts, and
19
+ an index that lists them all, as well as a map.resources :posts
20
+ declaration in config/routes.rb.
21
+
22
+ Examples:
23
+ `./script/generate coulda_scaffold post` # no attributes, view will be anemic
24
+ `./script/generate coulda_scaffold post title:string body:text published:boolean`
25
+ `./script/generate coulda_scaffold purchase order_id:integer amount:decimal`
@@ -0,0 +1,107 @@
1
+ class CouldaScaffoldGenerator < Rails::Generator::NamedBase
2
+
3
+ default_options :skip_timestamps => false,
4
+ :skip_migration => false,
5
+ :skip_factory => false
6
+
7
+ attr_reader :controller_name,
8
+ :controller_class_path,
9
+ :controller_file_path,
10
+ :controller_class_nesting,
11
+ :controller_class_nesting_depth,
12
+ :controller_class_name,
13
+ :controller_underscore_name,
14
+ :controller_singular_name,
15
+ :controller_plural_name
16
+
17
+ alias_method :controller_file_name, :controller_underscore_name
18
+ alias_method :controller_table_name, :controller_plural_name
19
+
20
+ def initialize(runtime_args, runtime_options = {})
21
+ super
22
+
23
+ if @name == @name.pluralize && !options[:force_plural]
24
+ logger.warning "Plural version of the model detected, using singularized version. Override with --force-plural."
25
+ @name = @name.singularize
26
+ end
27
+
28
+ @controller_name = @name.pluralize
29
+
30
+ base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
31
+ @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name)
32
+ @controller_singular_name = base_name.singularize
33
+
34
+ if @controller_class_nesting.empty?
35
+ @controller_class_name = @controller_class_name_without_nesting
36
+ else
37
+ @controller_class_name =
38
+ "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
39
+ end
40
+ end
41
+
42
+ def manifest
43
+ record do |m|
44
+ # Check for class naming collisions.
45
+ m.class_collisions(controller_class_path,
46
+ "#{controller_class_name}Controller", "#{controller_class_name}Helper")
47
+ m.class_collisions(class_path, "#{class_name}")
48
+
49
+ # Controller, helper, views, and test directories.
50
+ m.directory(File.join('app/models', class_path))
51
+ m.directory(File.join('app/controllers', controller_class_path))
52
+ m.directory(File.join('app/helpers', controller_class_path))
53
+ m.directory(File.join('app/views', controller_class_path, controller_file_name))
54
+ m.directory(File.join('test/functional', controller_class_path))
55
+ m.directory(File.join('test/unit', class_path))
56
+ m.directory(File.join('test/unit/helper', class_path))
57
+
58
+ for view in scaffold_views
59
+ m.template(
60
+ "view/#{view}.html.erb",
61
+ File.join('app/views', controller_class_path, controller_file_name, "#{view}.html.erb")
62
+ )
63
+ end
64
+
65
+ m.template(
66
+ 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
67
+ )
68
+
69
+ m.template("functional_test/shoulda_controller.rb", File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
70
+
71
+ m.template('helper.rb', File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb"))
72
+
73
+ m.template('helper_test.rb', File.join('test/unit/helper', class_path, "#{controller_file_name}_helper_test.rb"))
74
+
75
+ m.route_resources controller_file_name
76
+
77
+ m.dependency 'coulda_model', [name] + @args, :collision => :skip
78
+ end
79
+ end
80
+
81
+ protected
82
+
83
+ # Override with your own usage banner.
84
+ def banner
85
+ "Usage: #{$0} coulda_scaffold ModelName [field:type, field:type]"
86
+ end
87
+
88
+ def add_options!(opt)
89
+ opt.separator ''
90
+ opt.separator 'Options:'
91
+ opt.on("--skip-timestamps",
92
+ "Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
93
+ opt.on("--skip-migration",
94
+ "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
95
+ opt.on("--skip-factory",
96
+ "Don't generation a fixture file for this model") { |v| options[:skip_factory] = v}
97
+ end
98
+
99
+ def scaffold_views
100
+ %w[ index show new edit _form ]
101
+ end
102
+
103
+ def model_name
104
+ class_name.demodulize
105
+ end
106
+
107
+ end