require 'rails/generators/resource_helpers'
#require '../../leonardo_shared' #I'd like to share common code but it can't find that module :(
WINDOWS = (RUBY_PLATFORM =~ /dos|win32|cygwin/i) || (RUBY_PLATFORM =~ /(:?mswin|mingw)/)
CRLF = WINDOWS ? "\r\n" : "\n"
module Rails
module Generators
class LeoscaControllerGenerator < NamedBase
include ResourceHelpers
#include LeonardoShared
#puts 'rails:leosca_controller'
source_root File.expand_path('../templates', __FILE__)
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
class_option :seeds, :type => :boolean, :default => true, :description => "Create seeds to run with rake db:seed"
class_option :seeds_elements, :type => :string, :default => "30", :description => "Choose seeds elements", :banner => "NUMBER OF ARRAY ELEMENTS"
class_option :remote, :type => :boolean, :default => true, :description => "Enable ajax. You can also do later set remote to true into index view."
check_class_collision :suffix => "Controller"
class_option :orm, :banner => "NAME", :type => :string, :required => true,
:desc => "ORM to generate the controller for"
def create_controller_files
template 'controller.rb', File.join('app/controllers', class_path, "#{controller_file_name}_controller.rb")
end
hook_for :template_engine, :as => :leosca
hook_for :test_framework, :as => :scaffold
# Invoke the helper using the controller name (pluralized)
hook_for :helper, :as => :scaffold do |invoked|
invoke invoked, [ controller_name ]
end
def update_yaml_locales
#Inject model and attributes name into yaml files for i18n
path = "config/locales"
files = []
files = Dir["#{path}/??.yml"]
files.each do |file|
next unless File.exists?(file)
#Fields name
inject_into_file file, :after => "#Attributes zone - do not remove#{CRLF}" do
content = " #{file_name}:#{CRLF}"
attributes.each do |attribute|
content << " #{attribute.name}: \"#{camel_case attribute.name}\"#{CRLF}"
end
content << " op_new: \"New #{singular_table_name}\"#{CRLF}"
content << " op_edit: \"Editing #{singular_table_name}\"#{CRLF}"
content << " op_index: \"Listing #{plural_table_name}\"#{CRLF}"
content
end
#Model name
inject_into_file file, :after => "models: &models#{CRLF}" do
<<-FILE.gsub(/^ /, '')
#{file_name}: "#{file_name.capitalize}"
#{controller_name}: "#{controller_name.capitalize}"
FILE
end
#Formtastic
inject_into_file file, :after => " hints:#{CRLF}" do
content = " #{file_name}:#{CRLF}"
attributes.each do |attribute|
attr_name = attribute.name.gsub '_', ''
case attribute.type
when :integer, :decimal, :float
content << " #{attribute.name}: \"Fill the #{attr_name} with a#{"n" if attribute.type == :integer} #{attribute.type.to_s} number\"#{CRLF}"
when :boolean
content << " #{attribute.name}: \"Select if this #{file_name} should be #{attr_name} or not\"#{CRLF}"
when :string, :text
content << " #{attribute.name}: \"Choose a good #{attr_name} for this #{file_name}\"#{CRLF}"
when :date, :datetime, :time
content << " #{attribute.name}: \"Choose a #{attribute.type.to_s} for #{attr_name}\"#{CRLF}"
else
content << " #{attribute.name}: \"Choose a #{attr_name}\"#{CRLF}"
end
end
content
end
end
end
def update_layout_html
file = "app/views/layouts/_#{CONFIG[:default_style]}.html.erb"
inject_into_file file, :after => "#{CRLF}" do
<<-FILE.gsub(/^ /, '')
#{"<% if can? :read, #{class_name} -%>" if authorization?}
<%= t('models.#{controller_name}') %>
#{"<% end -%>" if authorization?}
FILE
end if File.exists?(file)
end
def update_ability_model
file = "app/models/ability.rb"
return unless File.exists?(file)
inject_into_file file, :before => " end\nend" do
<<-FILE.gsub(/^ /, '')
#can :read, #{class_name} if user.new_record? #Guest
can :read, #{class_name} if user.role? :guest #Registered guest
if user.role? :user
can :read, #{class_name}
can :update, #{class_name}
can :create, #{class_name}
end
if user.role? :manager
can :read, #{class_name}
can :update, #{class_name}
can :create, #{class_name}
can :destroy, #{class_name}
end
FILE
end
end
def add_seeds_db
return unless options.seeds? and options[:seeds_elements].to_i > 0
file = "db/seeds.rb"
append_file file do
items = []
attributes.each do |attribute|
items << attribute_to_hash(attribute)
end
row = "{ #{items.join(', ')} }"
#TODO: to have different values for every row
content = "#{CRLF}### Created by leosca controller generator ### #{CRLF}#{class_name}.create([#{CRLF}"
options[:seeds_elements].to_i.times do |n|
content << "#{row.gsub(/\#/, (n+1).to_s)},#{CRLF}"
end
content << "])#{CRLF}"
content
end if File.exists?(file)
end
def update_specs
file = "spec/spec_helper.rb"
return unless File.exists? file
check_attr_to_have, check_attr_to_not_have = get_attr_to_match
file = "spec/requests/#{plural_table_name}_spec.rb"
remove = <<-FILE.gsub(/^ /, '')
it "works! (now write some real specs)" do
# Run the generator again with the --webrat flag if you want to use webrat methods/matchers
get #{plural_table_name}_path
response.status.should be(200)
end
FILE
gsub_file file, remove, ""
inject_into_file file, :after => "describe \"GET /#{plural_table_name}\" do" do
<<-FILE.gsub(/^ /, '')
it "displays #{plural_table_name}" do
#{singular_table_name} = Factory(:#{singular_table_name})
visit #{plural_table_name}_path
login_view_as(:user_guest)
#save_and_open_page #uncomment to debug
page.should #{check_attr_to_have}
assert page.find("#tr\#{#{singular_table_name}.id}").visible?
end
it "checks ajax", :js => true do
#{singular_table_name} = Factory(:#{singular_table_name})
visit #{plural_table_name}_path
login_view_as(:user_manager)
page.should #{check_attr_to_have}
click_link "Destroy"
page.driver.browser.switch_to.alert.accept
#save_and_open_page #uncomment to debug
page.should #{check_attr_to_not_have}
assert !find("#tr\#{#{singular_table_name}.id}").visible?
end
FILE
end
inject_into_file file, :before => /^end/ do
items = []
attributes.each do |attribute|
items << attribute_to_requests(attribute)
end
<<-FILE.gsub(/^ /, '')
describe "POST /#{plural_table_name}" do
it "creates a new #{singular_table_name}" do
#{singular_table_name} = Factory.build(:#{singular_table_name})
visit new_#{singular_table_name}_path
login_view_as(:user)
#{items.join(CRLF)}
click_button "Create \#{I18n.t('models.#{singular_table_name}')}"
#save_and_open_page #uncomment to debug
page.should have_content(I18n.t(:created, :model => I18n.t('models.#{singular_table_name}')))
page.should #{check_attr_to_have}
end
end
FILE
end
file = "spec/factories.rb"
inject_into_file file, :after => "### Leonardo creates here below your factories ###" do
items = []
attributes.each do |attribute|
items << attribute_to_factories(attribute)
end
<<-FILE.gsub(/^ /, '')
factory :#{singular_table_name} do |#{singular_table_name[0..0]}|
#{items.join(CRLF)}
end
FILE
end if File.exists?(file)
end
protected
def authorization?
File.exists? "app/models/ability.rb"
end
def authentication?
return true if File.exists? "app/models/user.rb"
File.exists? "config/initializers/devise.rb"
end
def camel_case(str)
return str if str !~ /_/ && str =~ /[A-Z]+.*/
str.split('_').map { |i| i.capitalize }.join
end
def formtastic?
return false unless options.formtastic?
File.exists? "config/initializers/formtastic.rb"
end
def jquery_ui?
File.exists? "vendor/assets/javascripts/jquery-ui"
end
def pagination?
File.exists? "config/initializers/kaminari_config.rb"
end
def attribute_to_hash(attribute)
name = case attribute.type
when :references, :belongs_to then ":#{attribute.name}_id"
else ":#{attribute.name}"
end
value = case attribute.type
when :boolean then "true"
when :integer then "#"
when :float, :decimal then "#.46"
when :references, :belongs_to then "#"
when :date then "#{Time.now.strftime("%Y-%m-%d 00:00:00.000")}".inspect
when :datetime then "#{Time.now.strftime("%Y-%m-%d %H:%M:%S.000")}".inspect
when :time then "#{Time.now.strftime("%H:%M:%S.000")}".inspect
else "#{attribute.name.titleize}\#".inspect
end
" #{name} => #{value}"
end
def attribute_to_factories(attribute)
name = case attribute.type
when :references, :belongs_to then "#{singular_table_name[0..0]}.association "
when :boolean, :datetime, :time then "#{singular_table_name[0..0]}.#{attribute.name} "
else "#{singular_table_name[0..0]}.sequence(:#{attribute.name}) "
end
value = case attribute.type
when :boolean then "true"
when :integer then "{|n| n }"
when :float, :decimal then "{|n| n }"
when :references, :belongs_to then ":#{attribute.name}"
when :date then "{|n| n.month.ago }"
when :datetime then "#{Time.now.strftime("%Y-%m-%d %H:%M:%S.000")}".inspect
when :time then "#{Time.now.strftime("%H:%M:%S.000")}".inspect
else "{|n| \"#{attribute.name.titleize}\#{n}\" }"
end
" #{name} #{value}"
end
def attribute_to_requests(attribute)
case attribute.type
when :boolean then " check '#{singular_table_name}_#{attribute.name}' if #{singular_table_name}.#{attribute.name}"
when :references, :belongs_to then " select #{singular_table_name}.#{attribute.name}.name, :from => '#{singular_table_name}_#{attribute.name}_id'"
when :datetime, :time then ""
when :date then " fill_in '#{singular_table_name}_#{attribute.name}', :with => #{singular_table_name}.#{attribute.name}.strftime('%d/%m/%Y')"
else " fill_in '#{singular_table_name}_#{attribute.name}', :with => #{singular_table_name}.#{attribute.name}"
end
end
def get_attr_to_match
attributes.each do |attribute|
return "have_content(#{singular_table_name}.#{attribute.name})",
"have_no_content(#{singular_table_name}.#{attribute.name})" if attribute.type==:string
end
#If there are not string attributes
return "have_xpath('//table/tbody/tr')",
"have_no_xpath('//table/tbody/tr')"
end
end
end
end