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