summaryrefslogtreecommitdiff
path: root/lib/generators/nifty/scaffold/scaffold_generator.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/generators/nifty/scaffold/scaffold_generator.rb')
-rw-r--r--lib/generators/nifty/scaffold/scaffold_generator.rb344
1 files changed, 344 insertions, 0 deletions
diff --git a/lib/generators/nifty/scaffold/scaffold_generator.rb b/lib/generators/nifty/scaffold/scaffold_generator.rb
new file mode 100644
index 0000000..1283e17
--- /dev/null
+++ b/lib/generators/nifty/scaffold/scaffold_generator.rb
@@ -0,0 +1,344 @@
+require 'generators/nifty'
+require 'rails/generators/migration'
+require 'rails/generators/generated_attribute'
+
+module Nifty
+ module Generators
+ class ScaffoldGenerator < Base
+ include Rails::Generators::Migration
+ no_tasks { attr_accessor :scaffold_name, :model_attributes, :controller_actions }
+
+ argument :scaffold_name, :type => :string, :required => true, :banner => 'ModelName'
+ argument :args_for_c_m, :type => :array, :default => [], :banner => 'controller_actions and model:attributes'
+
+ class_option :skip_model, :desc => 'Don\'t generate a model or migration file.', :type => :boolean
+ class_option :skip_migration, :desc => 'Don\'t generate migration file for model.', :type => :boolean
+ class_option :skip_timestamps, :desc => 'Don\'t add timestamps to migration file.', :type => :boolean
+ class_option :skip_controller, :desc => 'Don\'t generate controller, helper, or views.', :type => :boolean
+ class_option :invert, :desc => 'Generate all controller actions except these mentioned.', :type => :boolean
+ class_option :namespace_model, :desc => 'If the resource is namespaced, include the model in the namespace.', :type => :boolean
+ class_option :haml, :desc => 'Generate HAML views instead of ERB.', :type => :boolean, :default => true
+
+ class_option :testunit, :desc => 'Use test/unit for test files.', :group => 'Test framework', :type => :boolean
+ class_option :rspec, :desc => 'Use RSpec for test files.', :group => 'Test framework', :type => :boolean
+ class_option :shoulda, :desc => 'Use shoulda for test files.', :group => 'Test framework', :type => :boolean
+
+ def initialize(*args, &block)
+ super
+
+ print_usage unless scaffold_name.underscore =~ /^[a-z][a-z0-9_\/]+$/
+
+ @controller_actions = []
+ @model_attributes = []
+ @skip_model = options.skip_model?
+ @namespace_model = options.namespace_model?
+ @invert_actions = options.invert?
+
+ args_for_c_m.each do |arg|
+ if arg == '!'
+ @invert_actions = true
+ elsif arg.include?(':')
+ @model_attributes << Rails::Generators::GeneratedAttribute.new(*arg.split(':'))
+ else
+ @controller_actions << arg
+ @controller_actions << 'create' if arg == 'new'
+ @controller_actions << 'update' if arg == 'edit'
+ end
+ end
+
+ @controller_actions.uniq!
+ @model_attributes.uniq!
+
+ if @invert_actions || @controller_actions.empty?
+ @controller_actions = all_actions - @controller_actions
+ end
+
+ if @model_attributes.empty?
+ @skip_model = true # skip model if no attributes
+ if model_exists?
+ model_columns_for_attributes.each do |column|
+ @model_attributes << Rails::Generators::GeneratedAttribute.new(column.name.to_s, column.type.to_s)
+ end
+ else
+ @model_attributes << Rails::Generators::GeneratedAttribute.new('name', 'string')
+ end
+ end
+ end
+
+ def add_gems
+ # add_gem "mocha", :group => :test
+ add_gem 'haml'
+ add_gem 'simple_form'
+ add_gem 'cancan'
+ end
+
+ def create_model
+ unless @skip_model
+ template 'model.rb', "app/models/#{model_path}.rb"
+ if test_framework == :rspec
+ template "tests/rspec/model.rb", "spec/models/#{model_path}_spec.rb"
+ # FUCK YOU FIXTURES, WE USE FACTORY GIRL.
+ # template 'fixtures.yml', "spec/fixtures/#{model_path.pluralize}.yml"
+ else
+ template "tests/#{test_framework}/model.rb", "test/unit/#{model_path}_test.rb"
+ template 'fixtures.yml', "test/fixtures/#{model_path.pluralize}.yml"
+ end
+ end
+ end
+
+ def create_migration
+ unless @skip_model || options.skip_migration?
+ migration_template 'migration.rb', "db/migrate/create_#{model_path.pluralize.gsub('/', '_')}.rb"
+ end
+ end
+
+ def create_controller
+ unless options.skip_controller?
+ template 'controller.rb', "app/controllers/#{plural_name}_controller.rb"
+
+ template 'helper.rb', "app/helpers/#{plural_name}_helper.rb"
+
+ controller_actions.each do |action|
+ if %w[index show new edit].include?(action) # Actions with templates
+ template "views/#{view_language}/#{action}.html.#{view_language}", "app/views/#{plural_name}/#{action}.html.#{view_language}"
+ end
+ end
+
+ # Move the index_core (can't do it on the top.)
+ template "views/#{view_language}/_index_core.html.#{view_language}", "app/views/#{plural_name}/_index_core.html.#{view_language}"
+
+
+ if form_partial?
+ template "views/#{view_language}/_form.html.#{view_language}", "app/views/#{plural_name}/_form.html.#{view_language}"
+ template "views/#{view_language}/_form_core.html.#{view_language}", "app/views/#{plural_name}/_form_core.html.#{view_language}"
+ end
+
+ namespaces = plural_name.split('/')
+ resource = namespaces.pop
+ route namespaces.reverse.inject("resources :#{resource}") { |acc, namespace|
+ "namespace(:#{namespace}){ #{acc} }"
+ }
+
+ if test_framework == :rspec
+ template "tests/#{test_framework}/controller.rb", "spec/controllers/#{plural_name}_controller_spec.rb"
+ else
+ template "tests/#{test_framework}/controller.rb", "test/functional/#{plural_name}_controller_test.rb"
+ end
+ end
+ end
+
+ def create_locales
+ template 'locale.yml', "config/locales/views/#{plural_name}/en.yml"
+ template 'locale_de.yml', "config/locales/views/#{plural_name}/de.yml"
+ # template 'locale.yml', "config/locales/views/#{plural_name}/es.yml"
+ # gsub_file("config/locales/views/#{plural_name}/es.yml", 'en:', 'es:')
+ # gsub_file("config/locales/views/#{plural_name}/de.yml", 'en:', 'de:')
+ end
+
+ def configuration
+ gsub_file('config/application.rb', "# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]",
+ "config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '*', '*', '*.{rb,yml}').to_s]")
+ end
+
+ private
+
+ def form_partial?
+ actions? :new, :edit
+ end
+
+ def all_actions
+ %w[index show new create edit update destroy]
+ end
+
+ def action?(name)
+ controller_actions.include? name.to_s
+ end
+
+ def actions?(*names)
+ names.all? { |name| action? name }
+ end
+
+ def singular_name
+ scaffold_name.underscore
+ end
+
+ def plural_name
+ scaffold_name.underscore.pluralize
+ end
+
+ def human_name
+ scaffold_name.humanize
+ end
+
+ def table_name
+ if scaffold_name.include?('::') && @namespace_model
+ plural_name.gsub('/', '_')
+ end
+ end
+
+ def class_name
+ if @namespace_model
+ scaffold_name.camelize
+ else
+ scaffold_name.split('::').last.camelize
+ end
+ end
+
+ def model_path
+ class_name.underscore
+ end
+
+ def plural_class_name
+ plural_name.camelize
+ end
+
+ def instance_name
+ if @namespace_model
+ singular_name.gsub('/','_')
+ else
+ singular_name.split('/').last
+ end
+ end
+
+ def instances_name
+ instance_name.pluralize
+ end
+
+ def controller_methods(dir_name)
+ controller_actions.map do |action|
+ read_template("#{dir_name}/#{action}.rb")
+ end.join("\n").strip
+ end
+
+ def render_form
+ if form_partial?
+ if options.haml?
+ "= render \"form\""
+ else
+ "<%= render \"form\" %>"
+ end
+ else
+ read_template("views/#{view_language}/_form.html.#{view_language}")
+ end
+ end
+
+ def item_resource
+ scaffold_name.underscore.gsub('/','_')
+ end
+
+ def items_path
+ if action? :index
+ "#{item_resource.pluralize}_path"
+ else
+ "root_path"
+ end
+ end
+
+ def item_path(options = {})
+ name = options[:instance_variable] ? "@#{instance_name}" : instance_name
+ suffix = options[:full_url] ? "url" : "path"
+ if options[:action].to_s == "new"
+ "new_#{item_resource}_#{suffix}"
+ elsif options[:action].to_s == "edit"
+ "edit_#{item_resource}_#{suffix}(#{name})"
+ else
+ if scaffold_name.include?('::') && !@namespace_model
+ namespace = singular_name.split('/')[0..-2]
+ "[:#{namespace.join(', :')}, #{name}]"
+ else
+ name
+ end
+ end
+ end
+
+ def item_url
+ if action? :show
+ item_path(:full_url => true, :instance_variable => true)
+ else
+ items_url
+ end
+ end
+
+ def items_url
+ if action? :index
+ item_resource.pluralize + '_url'
+ else
+ "root_url"
+ end
+ end
+
+ def item_path_for_spec(suffix = 'path')
+ if action? :show
+ "#{item_resource}_#{suffix}(assigns[:#{instance_name}])"
+ else
+ if suffix == 'path'
+ items_path
+ else
+ items_url
+ end
+ end
+ end
+
+ def item_path_for_test(suffix = 'path')
+ if action? :show
+ "#{item_resource}_#{suffix}(assigns(:#{instance_name}))"
+ else
+ if suffix == 'path'
+ items_path
+ else
+ items_url
+ end
+ end
+ end
+
+ def model_columns_for_attributes
+ class_name.constantize.columns.reject do |column|
+ column.name.to_s =~ /^(id|created_at|updated_at)$/
+ end
+ end
+
+ def view_language
+ options.haml? ? 'haml' : 'erb'
+ end
+
+ def test_framework
+ return @test_framework if defined?(@test_framework)
+ if options.testunit?
+ return @test_framework = :testunit
+ elsif options.rspec?
+ return @test_framework = :rspec
+ elsif options.shoulda?
+ return @test_framework = :shoulda
+ else
+ return @test_framework = default_test_framework
+ end
+ end
+
+ def default_test_framework
+ File.exist?(destination_path("spec")) ? :rspec : :testunit
+ end
+
+ def model_exists?
+ File.exist? destination_path("app/models/#{singular_name}.rb")
+ end
+
+ def read_template(relative_path)
+ ERB.new(File.read(find_in_source_paths(relative_path)), nil, '-').result(binding)
+ end
+
+ def destination_path(path)
+ File.join(destination_root, path)
+ end
+
+ # FIXME: Should be proxied to ActiveRecord::Generators::Base
+ # Implement the required interface for Rails::Generators::Migration.
+ def self.next_migration_number(dirname) #:nodoc:
+ if ActiveRecord::Base.timestamped_migrations
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
+ else
+ "%.3d" % (current_migration_number(dirname) + 1)
+ end
+ end
+ end
+ end
+end