class ScaffoldingSandbox
include ActionView::Helpers::ActiveRecordHelper
attr_accessor :singular_name, :suffix, :model_instance
def sandbox_binding
binding
end
def default_input_block
Proc.new { |record, column| "
| #{input(record, column.name)} |
\n" }
end
end
class ListHeadScaffoldingSandbox < ScaffoldingSandbox
def default_input_block
Proc.new { |record, column| "#{column.human_name} | " }
end
end
class ListLineScaffoldingSandbox < ScaffoldingSandbox
def default_input_block
Proc.new { |record, column| "#{record} #{column.human_name} | " }
end
end
class ShowScaffoldingSandbox < ScaffoldingSandbox
def default_input_block
Proc.new { |record, column| " | #{record} #{column.human_name} |
" }
end
end
class ActionView::Helpers::InstanceTag
def to_input_field_tag(field_type, options={})
field_meth = "#{field_type}_field"
case field_meth
when 'text_field'
%Q[]
when 'hidden_field'
%Q[]
when 'password_field'
%Q[]
end
end
def to_text_area_tag(options = {})
%Q[]
end
def to_date_select_tag(options = {})
%Q[todo render date select]
end
def to_datetime_select_tag(options = {})
%Q[todo render date select]
end
end
module Rails
module Generator
module Commands
class Create < Base
def multi_include_template(relative_source, relative_destination, template_options = {}, multi_assign_options = {})
options = template_options.dup
options[:assigns] ||= {}
multi_assign_options.each do |k,v|
options[:assigns][k] = render_template_part(v)
end
template(relative_source, relative_destination, options)
end
end
class Destroy < RewindBase
def multi_include_template(relative_source, relative_destination, template_options = {}, multi_assign_options = {})
end
end
class List < Base
def multi_include_template(relative_source, relative_destination, template_options = {}, multi_assign_options = {})
str = ""
multi_assign_options.each do |k,v|
str << v[:insert] << ' '
end
logger.template "#{str} inside #{relative_destination}"
end
end
class Update < Create
def multi_include_template(relative_source, relative_destination, template_options = {}, multi_assign_options = {})
begin
dest_file = destination_path(relative_destination)
source_to_update = File.readlines(dest_file).join
rescue Errno::ENOENT
logger.missing relative_destination
return
end
multi_assign_options.each do |k,v|
template_options = v
logger.refreshing "#{template_options[:insert].gsub(/\.rhtml/,'')} inside #{relative_destination}"
begin_mark = Regexp.quote(template_part_mark(template_options[:begin_mark], template_options[:mark_id]))
end_mark = Regexp.quote(template_part_mark(template_options[:end_mark], template_options[:mark_id]))
# Refreshing inner part of the template with freshly rendered part.
rendered_part = render_template_part(template_options)
source_to_update.gsub!(/#{begin_mark}.*?#{end_mark}/m, rendered_part)
end
File.open(dest_file, 'w') { |file| file.write(source_to_update) }
end
end
end
end
end
class MasterviewGenerator < Rails::Generator::NamedBase
attr_reader :controller_name,
:controller_class_path,
:controller_file_path,
:controller_class_nesting,
:controller_class_nesting_depth,
:controller_class_name,
:controller_singular_name,
:controller_plural_name
alias_method :controller_file_name, :controller_singular_name
alias_method :controller_view_dir_name, :controller_singular_name
alias_method :controller_masterview_name, :controller_singular_name
alias_method :controller_table_name, :controller_plural_name
def initialize(runtime_args, runtime_options = {})
super
@controller_name = args.shift || @name
base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
@controller_class_name_without_nesting, @controller_singular_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|
# Depend on model generator but skip if the model exists.
m.dependency 'model', [singular_name], :collision => :skip, :skip_migration => true
# Check for class naming collisions.
m.class_collisions controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}ControllerTest", "#{controller_class_name}Helper"
# Controller, helper, views, and test directories.
m.directory File.join('app/controllers', controller_class_path)
m.directory File.join('app/helpers', controller_class_path)
m.directory File.join('app/views', controller_class_path, controller_view_dir_name)
m.directory 'app/views/masterview'
m.directory File.join('test/functional', controller_class_path)
# Controller class, functional test, helper, and views.
m.template 'controller.rb',
File.join('app/controllers',
controller_class_path,
"#{controller_file_name}_controller.rb")
m.template 'functional_test.rb',
File.join('test/functional',
controller_class_path,
"#{controller_file_name}_controller_test.rb")
m.template 'helper.rb',
File.join('app/helpers',
controller_class_path,
"#{controller_file_name}_helper.rb")
# MasterView
m.template 'mvpreview.js',
File.join('public/javascripts',
"mvpreview.js")
m.multi_include_template "masterview.rhtml","app/views/masterview/#{controller_masterview_name}.html", {},
{
'form_inclusion' =>
{ :insert => 'form_scaffold.rhtml',
:sandbox => lambda { create_multi_sandbox('ScaffoldingSandbox') },
:begin_mark => 'form',
:end_mark => 'eoform',
:mark_id => singular_name
},
'list_head_inclusion' =>
{ :insert => 'fields_scaffold.rhtml',
:sandbox => lambda { create_multi_sandbox('ListHeadScaffoldingSandbox') },
:begin_mark => 'listhead',
:end_mark => 'eolisthead',
:mark_id => singular_name
},
'list_line_inclusion' =>
{ :insert => 'list_line_scaffold.rhtml',
:sandbox => lambda { create_multi_sandbox('ListLineScaffoldingSandbox') },
:begin_mark => 'listline',
:end_mark => 'eolistline',
:mark_id => singular_name
},
'show_inclusion' =>
{ :insert => 'show_scaffold.rhtml',
:sandbox => lambda { create_multi_sandbox('ShowScaffoldingSandbox') },
:begin_mark => 'show',
:end_mark => 'eoshow',
:mark_id => singular_name
}
}
m.template 'style.css', 'public/stylesheets/scaffold.css'
end
end
protected
# Override with your own usage banner.
def banner
"Usage: #{$0} masterview ModelName [ControllerName] [action, ...]"
end
def scaffold_views
%w(list show new edit destroy)
end
def scaffold_actions
scaffold_views + %w(index)
end
def unscaffolded_actions
args - scaffold_actions
end
def suffix
"_#{singular_name}" if options[:suffix]
end
def model_name
class_name.demodulize
end
def create_sandbox
sandbox = ScaffoldingSandbox.new
sandbox.singular_name = singular_name
begin
sandbox.model_instance = model_instance
sandbox.instance_variable_set("@#{singular_name}", sandbox.model_instance)
rescue ActiveRecord::StatementInvalid => e
logger.error "Before updating scaffolding from new DB schema, try creating a table for your model (#{class_name})"
raise SystemExit
end
sandbox.suffix = suffix
sandbox
end
def create_multi_sandbox( sandbox_class_name )
sandbox = eval("#{sandbox_class_name}.new")
sandbox.singular_name = singular_name
begin
sandbox.model_instance = model_instance
sandbox.instance_variable_set("@#{singular_name}", sandbox.model_instance)
rescue ActiveRecord::StatementInvalid => e
logger.error "Before updating scaffolding from new DB schema, try creating a table for your model (#{class_name})"
raise SystemExit
end
sandbox.suffix = suffix
sandbox
end
def model_instance
base = class_nesting.split('::').inject(Object) do |base, nested|
break base.const_get(nested) if base.const_defined?(nested)
base.const_set(nested, Module.new)
end
unless base.const_defined?(@class_name_without_nesting)
base.const_set(@class_name_without_nesting, Class.new(ActiveRecord::Base))
end
class_name.constantize.new
end
end