michel-dry_scaffold 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/CHANGELOG.textile +51 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.textile +461 -0
  4. data/Rakefile +48 -0
  5. data/TODO.textile +40 -0
  6. data/bin/dmodel +3 -0
  7. data/bin/dry_model +3 -0
  8. data/bin/dry_scaffold +3 -0
  9. data/bin/dscaffold +3 -0
  10. data/config/scaffold.yml +34 -0
  11. data/generators/dmodel/dmodel_generator.rb +15 -0
  12. data/generators/dry_model/USAGE +9 -0
  13. data/generators/dry_model/dry_model_generator.rb +134 -0
  14. data/generators/dry_model/prototypes/active_record_migration.rb +17 -0
  15. data/generators/dry_model/prototypes/active_record_model.rb +9 -0
  16. data/generators/dry_model/prototypes/fixture_data/active_record_fixtures.yml +3 -0
  17. data/generators/dry_model/prototypes/fixture_data/factory_girl_factories.rb +4 -0
  18. data/generators/dry_model/prototypes/fixture_data/machinist_blueprints.rb +8 -0
  19. data/generators/dry_model/prototypes/tests/rspec/unit_test.rb +9 -0
  20. data/generators/dry_model/prototypes/tests/shoulda/unit_test.rb +20 -0
  21. data/generators/dry_model/prototypes/tests/test_unit/unit_test.rb +15 -0
  22. data/generators/dry_model/templates/models/active_record_migration.rb +23 -0
  23. data/generators/dry_model/templates/models/active_record_model.rb +15 -0
  24. data/generators/dry_model/templates/models/fixture_data/active_record_fixtures.yml +6 -0
  25. data/generators/dry_model/templates/models/fixture_data/factory_girl_factories.rb +5 -0
  26. data/generators/dry_model/templates/models/fixture_data/machinist_blueprints.rb +9 -0
  27. data/generators/dry_model/templates/models/tests/rspec/unit_test.rb +11 -0
  28. data/generators/dry_model/templates/models/tests/shoulda/unit_test.rb +23 -0
  29. data/generators/dry_model/templates/models/tests/test_unit/unit_test.rb +17 -0
  30. data/generators/dry_scaffold/USAGE +11 -0
  31. data/generators/dry_scaffold/dry_scaffold_generator.rb +415 -0
  32. data/generators/dry_scaffold/prototypes/controllers/action_controller.rb +135 -0
  33. data/generators/dry_scaffold/prototypes/controllers/inherited_resources_controller.rb +25 -0
  34. data/generators/dry_scaffold/prototypes/controllers/tests/rspec/functional_test.rb +57 -0
  35. data/generators/dry_scaffold/prototypes/controllers/tests/shoulda/functional_test.rb +99 -0
  36. data/generators/dry_scaffold/prototypes/controllers/tests/test_unit/functional_test.rb +70 -0
  37. data/generators/dry_scaffold/prototypes/helpers/helper.rb +3 -0
  38. data/generators/dry_scaffold/prototypes/helpers/tests/rspec/unit_test.rb +9 -0
  39. data/generators/dry_scaffold/prototypes/helpers/tests/shoulda/unit_test.rb +9 -0
  40. data/generators/dry_scaffold/prototypes/helpers/tests/test_unit/unit_test.rb +9 -0
  41. data/generators/dry_scaffold/prototypes/views/builder/index.atom.builder +20 -0
  42. data/generators/dry_scaffold/prototypes/views/builder/index.rss.builder +21 -0
  43. data/generators/dry_scaffold/prototypes/views/haml/_form.html.haml +3 -0
  44. data/generators/dry_scaffold/prototypes/views/haml/_item.html.haml +9 -0
  45. data/generators/dry_scaffold/prototypes/views/haml/edit.html.haml +10 -0
  46. data/generators/dry_scaffold/prototypes/views/haml/index.html.haml +17 -0
  47. data/generators/dry_scaffold/prototypes/views/haml/layout.html.haml +18 -0
  48. data/generators/dry_scaffold/prototypes/views/haml/new.html.haml +10 -0
  49. data/generators/dry_scaffold/prototypes/views/haml/show.html.haml +13 -0
  50. data/generators/dry_scaffold/templates/controllers/action_controller.rb +250 -0
  51. data/generators/dry_scaffold/templates/controllers/inherited_resources_controller.rb +36 -0
  52. data/generators/dry_scaffold/templates/controllers/tests/rspec/functional_test.rb +85 -0
  53. data/generators/dry_scaffold/templates/controllers/tests/shoulda/functional_test.rb +90 -0
  54. data/generators/dry_scaffold/templates/controllers/tests/test_unit/functional_test.rb +87 -0
  55. data/generators/dry_scaffold/templates/helpers/helper.rb +3 -0
  56. data/generators/dry_scaffold/templates/helpers/tests/rspec/unit_test.rb +9 -0
  57. data/generators/dry_scaffold/templates/helpers/tests/shoulda/unit_test.rb +9 -0
  58. data/generators/dry_scaffold/templates/helpers/tests/test_unit/unit_test.rb +9 -0
  59. data/generators/dry_scaffold/templates/views/builder/index.atom.builder +20 -0
  60. data/generators/dry_scaffold/templates/views/builder/index.rss.builder +21 -0
  61. data/generators/dry_scaffold/templates/views/haml/_form.html.haml +13 -0
  62. data/generators/dry_scaffold/templates/views/haml/_item.html.haml +10 -0
  63. data/generators/dry_scaffold/templates/views/haml/edit.html.haml +18 -0
  64. data/generators/dry_scaffold/templates/views/haml/index.html.haml +38 -0
  65. data/generators/dry_scaffold/templates/views/haml/layout.html.haml +19 -0
  66. data/generators/dry_scaffold/templates/views/haml/new.html.haml +18 -0
  67. data/generators/dry_scaffold/templates/views/haml/show.html.haml +13 -0
  68. data/generators/dscaffold/dscaffold_generator.rb +15 -0
  69. data/lib/dry_generator.rb +197 -0
  70. data/lib/dry_scaffold/tasks.rb +5 -0
  71. data/lib/setup_helper.rb +36 -0
  72. data/rails/init.rb +3 -0
  73. data/tasks/dry_scaffold.rake +95 -0
  74. metadata +132 -0
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ NAME = "michel-dry_scaffold"
6
+ SUMMARY = %Q{A DRYer scaffold generator for Rails. Generates dry semantic and standards compliant views, and dry RESTful controllers.}
7
+ HOMEPAGE = "http://github.com/michel/#{NAME}/tree/master"
8
+ AUTHOR = "Jonas Grimfelt,Michel de Graaf"
9
+ EMAIL = "grimen@gmail.com, michel@re-invention.nl"
10
+ SUPPORT_FILES = %w(README.textile TODO.textile CHANGELOG.textile)
11
+
12
+ begin
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ gem.name = NAME
16
+ gem.summary = SUMMARY
17
+ gem.description = SUMMARY
18
+ gem.homepage = HOMEPAGE
19
+ gem.author = AUTHOR
20
+ gem.email = EMAIL
21
+
22
+ gem.require_paths = %w{lib}
23
+ gem.files = %w(MIT-LICENSE Rakefile) + SUPPORT_FILES + Dir.glob(File.join('{bin,config,generators,lib,rails,tasks}', '**', '*'))
24
+ gem.executables = %w(dscaffold dry_scaffold dmodel dry_model)
25
+ gem.extra_rdoc_files = SUPPORT_FILES
26
+ end
27
+ rescue LoadError
28
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
29
+ end
30
+
31
+ desc %Q{Run unit tests for "#{NAME}".}
32
+ task :default => :test
33
+
34
+ desc %Q{Run unit tests for "#{NAME}".}
35
+ Rake::TestTask.new(:test) do |test|
36
+ test.libs << 'lib'
37
+ test.pattern = 'test/**/*_test.rb'
38
+ test.verbose = true
39
+ end
40
+
41
+ desc %Q{Generate documentation for "#{NAME}".}
42
+ Rake::RDocTask.new(:rdoc) do |rdoc|
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = NAME
45
+ rdoc.options << '--line-numbers' << '--inline-source' << '--charset=UTF-8'
46
+ rdoc.rdoc_files.include(SUPPORT_FILES)
47
+ rdoc.rdoc_files.include(File.join('lib', '**', '*.rb'))
48
+ end
data/TODO.textile ADDED
@@ -0,0 +1,40 @@
1
+ h1. TODO
2
+
3
+ h2. Next
4
+
5
+ * Bug/Issue: InheritedResources functional testing issue.
6
+ * Feature: RSpec-templates?
7
+ * Optimization: Write even better functional tests for REST-actions. Goal: Killer-tests, i.e. "best practice"-tests. Suggestion: Routing, formats, ...
8
+ * Feature: Auto-detection of testing frameworks in working project.
9
+
10
+ h2. Maybe
11
+
12
+ * Feature: Check for overridden templates in: RAILS_ROOT/lib/dry_scaffold/templates/
13
+ * Feature: Handle belongs_to, i.e. specify MODEL --belongs-to PARENT_MODEL, which generates proper routes, proper before-filters if inherited_resources-controller, adding belongs_to-association in model, and correct form_for arguments.
14
+ * Feature: Builder for podcast-feed, similar to RSS/Atom-builders. http://wiki.github.com/radiant/radiant/host-a-podcast
15
+ * Tests: Generator tests. =P (Not very straightforward...)
16
+
17
+ h2. Issues
18
+
19
+ * Contact José regarding the InheritedResources-issue:
20
+
21
+ ActionController::RoutingError: parrot_url failed to generate from {:controller=>"parrots", :id=>#<Parrot id: nil, name: "Hello", created_at: "2009-07-21 18:53:25", updated_at: "2009-07-21 18:53:25">, :action=>"show"}, expected: {:controller=>"parrots", :action=>"show"}, diff: {:id=>#<Parrot id: nil, name: "Hello", created_at: "2009-07-21 18:53:25", updated_at: "2009-07-21 18:53:25">}
22
+ (eval):16:in `parrot_url'
23
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/url_helpers.rb:194:in `resource_url'
24
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base_helpers.rb:311:in `send'
25
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base_helpers.rb:311:in `parse_redirect_url'
26
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base.rb:79:in `create'
27
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/respond_to.rb:301:in `call'
28
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/respond_to.rb:301:in `respond_any'
29
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/respond_to.rb:233:in `respond_to'
30
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base_helpers.rb:283:in `respond_to_with_dual_blocks'
31
+ /opt/local/lib/ruby/gems/1.8/gems/josevalim-inherited_resources-0.7.3/lib/inherited_resources/base.rb:78:in `create'
32
+ haml (2.0.9) rails/./lib/sass/plugin/rails.rb:19:in `process'
33
+ /test/functional/donkeys_controller_test.rb:8:in `test_create'
34
+
35
+ test 'create' do
36
+ Donkey.any_instance.expects(:save).returns(true)
37
+ @donkey = donkeys(:basic)
38
+ post :create, :donkey => @donkey.attributes # <<<<<<<<<<<<< donkeys_controller_test.rb:8
39
+ assert_response :redirect
40
+ end
data/bin/dmodel ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ `ruby script/generate dmodel #{ARGV.join(' ')}`
data/bin/dry_model ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ `ruby script/generate dry_model #{ARGV.join(' ')}`
data/bin/dry_scaffold ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ `ruby script/generate dry_scaffold #{ARGV.join(' ')}`
data/bin/dscaffold ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ `ruby script/generate dscaffold #{ARGV.join(' ')}`
@@ -0,0 +1,34 @@
1
+ ---
2
+ dry_scaffold:
3
+ args:
4
+ actions: index,show,new,edit,create,update,destroy
5
+ formats: html,js,xml,json
6
+ options:
7
+ formtastic: true
8
+ resourceful: true
9
+ search: true
10
+ pagination: true
11
+ layout: false
12
+ views: true
13
+ helpers: true
14
+ tests: true
15
+ controller_tests: true
16
+ test_unit: true
17
+ shoulda: false
18
+ rspec: false
19
+ fixtures: true
20
+ fgirl: false
21
+ machinist: false
22
+ object_daddy: false
23
+ dry_model:
24
+ options:
25
+ migration: true
26
+ timestamps: true
27
+ tests: true
28
+ test_unit: true
29
+ shoulda: false
30
+ rspec: false
31
+ fixtures: true
32
+ fgirl: false
33
+ machinist: false
34
+ object_daddy: false
@@ -0,0 +1,15 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'dry_model', 'dry_model_generator')
2
+
3
+ class DmodelGenerator < DryModelGenerator
4
+
5
+ def initialize(runtime_args, runtime_options = {})
6
+ super
7
+ # Make Rails look for templates within generator "dry_model" path
8
+ @source_root = options[:source] || File.join(spec.path, '..', 'dry_model', 'templates')
9
+ end
10
+
11
+ def usage_message
12
+ File.read(File.join(spec.path, '..', 'dry_model', 'USAGE')) rescue ''
13
+ end
14
+
15
+ end
@@ -0,0 +1,9 @@
1
+ NAME
2
+ dry_model/dmodel - A Rails scaffold generator that generates DRYer, cleaner, and more useful code - for models.
3
+
4
+ DESCRIPTION
5
+ A replacement for the Rails model generator - a part of the dry_generator toolset.
6
+
7
+ EXAMPLE
8
+ ./script/generate dmodel GoldFish name:string about:text _indexes:name --fgirl
9
+ ./script/generate dmodel Frog name:string about:text _indexes:name,name+about --fixtures
@@ -0,0 +1,134 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'dry_generator'))
2
+
3
+ class DryModelGenerator < DryGenerator
4
+
5
+ # Banner: Generator arguments and options.
6
+ BANNER_ARGS = [
7
+ "[_indexes:field,field+field,field,...]"
8
+ ].freeze
9
+ BANNER_OPTIONS = [
10
+ "[--skip-timestamps]",
11
+ "[--skip-migration]"
12
+ ].freeze
13
+
14
+ # Paths.
15
+ MODELS_PATH = File.join('app', 'models').freeze
16
+ MIGRATIONS_PATH = File.join('db', 'migrate').freeze
17
+
18
+ attr_reader :indexes,
19
+ :references
20
+
21
+ def initialize(runtime_args, runtime_options = {})
22
+ super(runtime_args, runtime_options)
23
+
24
+ @attributes ||= []
25
+ args_for_model = []
26
+
27
+ @args.each do |arg|
28
+ arg_entities = arg.split(':')
29
+ if arg =~ /^#{NON_ATTR_ARG_KEY_PREFIX}/
30
+ if arg =~ /^#{NON_ATTR_ARG_KEY_PREFIX}index/
31
+ arg_indexes = arg_entities[1].split(',').compact.uniq
32
+ @indexes = arg_indexes.collect do |index|
33
+ if index =~ /\+/
34
+ index.split('+').collect { |i| i.downcase.to_sym }
35
+ else
36
+ index.downcase.to_sym
37
+ end
38
+ end
39
+ end
40
+ else
41
+ @attributes << Rails::Generator::GeneratedAttribute.new(*arg_entities)
42
+ args_for_model << arg
43
+ end
44
+ end
45
+
46
+ @args = args_for_model
47
+ @references = attributes.select(&:reference?)
48
+ @options = DEFAULT_OPTIONS.merge(options)
49
+ end
50
+
51
+ def manifest
52
+ record do |m|
53
+ # Check for class naming collisions.
54
+ m.class_collisions class_name, "#{class_name}Test"
55
+
56
+ # Model.
57
+ m.directory File.join(MODELS_PATH, class_path)
58
+ m.template File.join('models', 'active_record_model.rb'),
59
+ File.join(MODELS_PATH, class_path, "#{file_name}.rb")
60
+
61
+ # Model Tests.
62
+ unless options[:skip_tests]
63
+ model_tests_path = File.join(TEST_PATHS[test_framework], UNIT_TESTS_PATH[test_framework])
64
+ m.directory File.join(model_tests_path, class_path)
65
+ m.template File.join('models', 'tests', "#{test_framework}", 'unit_test.rb'),
66
+ File.join(model_tests_path, class_path, "#{file_name}_#{TEST_POST_FIX[test_framework]}.rb")
67
+
68
+ # Fixtures/Factories.
69
+ if options[:fixtures]
70
+ fixtures_path = File.join(TEST_PATHS[test_framework], 'fixtures')
71
+ m.directory File.join(fixtures_path, class_path)
72
+ m.template File.join('models', 'fixture_data', 'active_record_fixtures.yml'),
73
+ File.join(fixtures_path, class_path, "#{table_name}.yml")
74
+ end
75
+ if options[:factory_girl]
76
+ factory_girl_path = File.join(TEST_PATHS[test_framework], 'factories')
77
+ m.directory File.join(factory_girl_path, class_path)
78
+ m.template File.join('models', 'fixture_data', 'factory_girl_factories.rb'),
79
+ File.join(factory_girl_path, class_path, "#{plural_name}.rb")
80
+ end
81
+ if options[:machinist]
82
+ machinist_path = File.join(TEST_PATHS[test_framework], 'blueprints')
83
+ m.directory File.join(machinist_path, class_path)
84
+ m.template File.join('models', 'fixture_data', 'machinist_blueprints.rb'),
85
+ File.join(machinist_path, class_path, "#{plural_name}.rb")
86
+ end
87
+ # NOTE: :object_daddy handled in model
88
+ end
89
+
90
+ # Migration.
91
+ unless options[:skip_migration]
92
+ m.migration_template File.join('models', 'active_record_migration.rb'), MIGRATIONS_PATH,
93
+ :assigns => {:migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"},
94
+ :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
95
+ end
96
+ end
97
+ end
98
+
99
+ protected
100
+
101
+ def add_options!(opt)
102
+ super(opt)
103
+
104
+ opt.separator ' '
105
+ opt.separator 'Model Options:'
106
+
107
+ opt.on("--skip-timestamps", "Don't add timestamps to the migration file.") do |v|
108
+ options[:skip_timestamps] = v
109
+ end
110
+
111
+ opt.on("--skip-migration", "Skip generation of migration file.") do |v|
112
+ options[:skip_migration] = v
113
+ end
114
+
115
+ opt.on("--skip-tests", "Skip generation of tests.") do |v|
116
+ options[:skip_tests] = v
117
+ end
118
+
119
+ opt.separator ' '
120
+ end
121
+
122
+ def banner_args
123
+ [BANNER_ARGS, super].flatten.join(' ')
124
+ end
125
+
126
+ def banner_options
127
+ [BANNER_OPTIONS, super].flatten.join(' ')
128
+ end
129
+
130
+ def banner
131
+ [super, banner_args, banner_options].join(' ')
132
+ end
133
+
134
+ end
@@ -0,0 +1,17 @@
1
+ class CreateDucks < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :resources, :force => true do |t|
4
+ t.string :name
5
+ t.text :description
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :resources, :name
11
+ add_index :resources, [:name, :description]
12
+ end
13
+
14
+ def self.down
15
+ drop_table :resources
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ class Duck < ActiveRecord::Base
2
+
3
+ belongs_to :owner
4
+
5
+ # object_daddy
6
+ generator_for(:name) { "AString" }
7
+ generator_for(:description) { "SomeText" }
8
+
9
+ end
@@ -0,0 +1,3 @@
1
+ default:
2
+ name: "AString"
3
+ description: "SomeText"
@@ -0,0 +1,4 @@
1
+ Factory.define :duck, :class => Duck do |f|
2
+ f.name "AString"
3
+ f.description "SomeText"
4
+ end
@@ -0,0 +1,8 @@
1
+ Sham.define do
2
+
3
+ end
4
+
5
+ Resource.blueprint do
6
+ name { "AString" }
7
+ description { "SomeText" }
8
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe DuckTest do
4
+ fixtures :ducks
5
+
6
+ it "should be valid" do
7
+ DuckTest.new.should be_valid
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class DuckTest < ActiveRecord::TestCase
4
+
5
+ fixtures :ducks
6
+
7
+ should_have_db_column :name
8
+ should_have_db_column :description
9
+
10
+ context "A test context" do
11
+ setup do
12
+
13
+ end
14
+
15
+ should 'test something' do
16
+ assert true
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,15 @@
1
+ require 'test_helper'
2
+
3
+ class DuckTest < ActiveRecord::TestCase
4
+
5
+ fixtures :ducks
6
+
7
+ setup do
8
+
9
+ end
10
+
11
+ test 'something' do
12
+ assert true
13
+ end
14
+
15
+ end
@@ -0,0 +1,23 @@
1
+ class <%= migration_name %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= table_name %> do |t|
4
+ <% attributes.each do |attribute| -%>
5
+ t.<%= attribute.type %> :<%= attribute.name %>
6
+ <% end -%>
7
+
8
+ <% unless options[:skip_timestamps] -%>
9
+ t.timestamps
10
+ <% end -%>
11
+ end
12
+ <% unless indexes.blank? -%>
13
+
14
+ <% indexes.each do |index| -%>
15
+ add_index :<%= table_name %>, <%= index.is_a?(Array) ? "[:#{index.join(', :')}]" : ":#{index}" %>
16
+ <% end -%>
17
+ <% end -%>
18
+ end
19
+
20
+ def self.down
21
+ drop_table :<%= table_name %>
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+
3
+ <% unless references.empty? -%>
4
+ <% references.each do |attribute| -%>
5
+ belongs_to :<%= attribute.name %>
6
+ <% end -%>
7
+
8
+ <% end -%>
9
+ <% if options[:object_daddy] -%>
10
+ <% attributes.each do |attribute| -%>
11
+ generator_for(:<%= attribute.name %>) { <%= attribute.default_for_factory %> }
12
+ <% end -%>
13
+
14
+ <% end -%>
15
+ end