jeffp-wizardly 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +29 -24
- data/lib/jeffp-wizardly.rb +1 -0
- data/lib/validation_group.rb +18 -3
- data/lib/wizardly/action_controller.rb +0 -1
- data/lib/wizardly/wizard.rb +1 -0
- data/lib/wizardly/wizard/configuration.rb +11 -3
- data/lib/wizardly/wizard/configuration/methods.rb +77 -68
- data/lib/wizardly/wizard/page.rb +1 -0
- data/rails_generators/wizardly_app/templates/wizardly.rake +9 -5
- data/rails_generators/wizardly_app/wizardly_app_generator.rb +1 -1
- data/rails_generators/wizardly_scaffold/templates/form.html.haml.erb +22 -0
- data/rails_generators/wizardly_scaffold/templates/layout.html.haml.erb +10 -0
- data/rails_generators/wizardly_scaffold/wizardly_scaffold_generator.rb +18 -10
- metadata +5 -2
    
        data/README.rdoc
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            = wizardly
         | 
| 2 2 |  | 
| 3 | 
            -
            +wizardly+  | 
| 3 | 
            +
            +wizardly+ creates a multi-step wizard for any ActiveRecord model in three steps.
         | 
| 4 4 |  | 
| 5 5 | 
             
            == Resources
         | 
| 6 6 |  | 
| @@ -14,13 +14,13 @@ Source | |
| 14 14 |  | 
| 15 15 | 
             
            Install
         | 
| 16 16 |  | 
| 17 | 
            -
            * sudo gem install jeffp-wizardly --source=http://gems.github.com
         | 
| 17 | 
            +
            * sudo gem install jeffp-wizardly --source=http://http://gems.github.com
         | 
| 18 18 |  | 
| 19 19 | 
             
            == Description
         | 
| 20 20 |  | 
| 21 21 | 
             
            +wizardly+ builds on Alex Kira's +validation_group+ plugin code to 
         | 
| 22 22 | 
             
            DRY up the Rails MVC implementation of a wizard.  In three easy steps, +wizardly+
         | 
| 23 | 
            -
            produces the scaffolding and controller of a  | 
| 23 | 
            +
            produces the scaffolding and controller of a multi-step wizard.
         | 
| 24 24 |  | 
| 25 25 | 
             
            Features include:
         | 
| 26 26 | 
             
            * Model-based definition
         | 
| @@ -32,11 +32,15 @@ Features include: | |
| 32 32 |  | 
| 33 33 | 
             
            == Setup
         | 
| 34 34 |  | 
| 35 | 
            -
             | 
| 35 | 
            +
            Put the following in your application's config block in config/environment.rb
         | 
| 36 36 |  | 
| 37 | 
            -
               | 
| 37 | 
            +
              config.gem 'jeffp-wizardly', :lib=>'wizardly' 
         | 
| 38 38 |  | 
| 39 | 
            -
             | 
| 39 | 
            +
            and run the install gems rake task on your application
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              rake gems:install
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            For any rails app, run the following to install wizardly rake tasks (optional)
         | 
| 40 44 |  | 
| 41 45 | 
             
              ./script/generate wizardly_app
         | 
| 42 46 |  | 
| @@ -55,7 +59,7 @@ Step 1: Define validation groups for your model. | |
| 55 59 |  | 
| 56 60 | 
             
            Step 2: Tell your controller to act 'wizardly'.
         | 
| 57 61 |  | 
| 58 | 
            -
              class SignupController <  | 
| 62 | 
            +
              class SignupController < ApplicationController
         | 
| 59 63 | 
             
                act_wizardly_for :user
         | 
| 60 64 | 
             
              end
         | 
| 61 65 |  | 
| @@ -100,16 +104,16 @@ uses the HTTP_REFERER for both cases.  What if there is no referer?  The control | |
| 100 104 | 
             
            raises a RedirectNotDefined error.  Let's remedy this problem with some options
         | 
| 101 105 | 
             
            in the macro.
         | 
| 102 106 |  | 
| 103 | 
            -
              class SignupController <  | 
| 107 | 
            +
              class SignupController < ApplicationController
         | 
| 104 108 | 
             
                act_wizardly_for :user, :completed=>'/main/finished', 
         | 
| 105 | 
            -
                  :canceled=> | 
| 109 | 
            +
                  :canceled=>{:controller=>:main, :action=>:canceled}
         | 
| 106 110 | 
             
              end
         | 
| 107 111 |  | 
| 108 112 | 
             
            Now whether the user completes or cancels the wizard, the controller knows
         | 
| 109 113 | 
             
            how to redirect.  Alternately, if you want to redirect to the same page 
         | 
| 110 114 | 
             
            for both cases
         | 
| 111 115 |  | 
| 112 | 
            -
              class SignupController <  | 
| 116 | 
            +
              class SignupController < ApplicationController
         | 
| 113 117 | 
             
                act_wizardly_for :user, :redirect=>'/main'
         | 
| 114 118 | 
             
              end
         | 
| 115 119 |  | 
| @@ -119,11 +123,11 @@ Here's a list of options you can use in the macro | |
| 119 123 |  | 
| 120 124 | 
             
              :completed => '/main/finished'
         | 
| 121 125 | 
             
              :canceled => {:controller=>'main', :action=>'canceled'}
         | 
| 122 | 
            -
              :skip =>  | 
| 126 | 
            +
              :skip => true
         | 
| 123 127 | 
             
              :mask_fields => [:password, :password_confirmation] (by default)
         | 
| 124 128 |  | 
| 125 | 
            -
             | 
| 126 | 
            -
            The :mask_fields options tells the scaffold generator which fields  | 
| 129 | 
            +
            Setting the :skip option to +true+ tells the scaffold helpers to include or exclude a skip button on each page.  
         | 
| 130 | 
            +
            The :mask_fields options tells the scaffold generator which fields to generate as 'type=password' fields.
         | 
| 127 131 |  | 
| 128 132 | 
             
            === Buttons
         | 
| 129 133 |  | 
| @@ -131,7 +135,7 @@ The wizardly controller defines five default button functions: next, back, skip, | |
| 131 135 | 
             
            cancel, and finish.  All but :skip are used in the scaffolding by default.  You
         | 
| 132 136 | 
             
            can add :skip functionality to all pages by adding an option to the macro
         | 
| 133 137 |  | 
| 134 | 
            -
              class SignupController <  | 
| 138 | 
            +
              class SignupController < ApplicationController
         | 
| 135 139 | 
             
                act_wizardly_for :user, :redirect=>'/main', :skip=>true
         | 
| 136 140 | 
             
              end
         | 
| 137 141 |  | 
| @@ -147,10 +151,10 @@ for the developer to change the processing.  Here's an example.  Say our model | |
| 147 151 | 
             
            declares a :step4 validation_group with :username, :password, and 
         | 
| 148 152 | 
             
            :password_confirmation fields.  We'd like to handle this step specifically.
         | 
| 149 153 |  | 
| 150 | 
            -
              class SignupController <  | 
| 154 | 
            +
              class SignupController < ApplicationController
         | 
| 151 155 | 
             
                act_wizardly_for :user, :redirect=>'/main'
         | 
| 152 156 |  | 
| 153 | 
            -
                def  | 
| 157 | 
            +
                def on_invalid_step4_form
         | 
| 154 158 | 
             
                  #clear the password field if errors
         | 
| 155 159 | 
             
                  @user[:password] = ''
         | 
| 156 160 | 
             
                  @user[:password_confirmation] = ''
         | 
| @@ -162,13 +166,14 @@ validation_group. | |
| 162 166 |  | 
| 163 167 | 
             
            Every page has a set of callbacks.  Here's the list for our :step1 page.
         | 
| 164 168 |  | 
| 165 | 
            -
              def  | 
| 166 | 
            -
              def  | 
| 167 | 
            -
              def  | 
| 168 | 
            -
              def  | 
| 169 | 
            -
              def  | 
| 170 | 
            -
              def  | 
| 171 | 
            -
              def  | 
| 169 | 
            +
              def on_get_step1_form; end    
         | 
| 170 | 
            +
              def on_post_step1_form; end
         | 
| 171 | 
            +
              def on_invalid_step1_form; end 
         | 
| 172 | 
            +
              def on_step1_form_next; end   
         | 
| 173 | 
            +
              def on_step1_form_back; end
         | 
| 174 | 
            +
              def on_step1_form_cancel; end
         | 
| 175 | 
            +
              def on_step1_form_finish; end
         | 
| 176 | 
            +
              def on_step1_form_skip; end
         | 
| 172 177 |  | 
| 173 178 | 
             
            Each callback is defined for the controller object, thus giving it access to all
         | 
| 174 179 | 
             
            controller variables and methods just as any other action method.  Each callback
         | 
| @@ -190,7 +195,7 @@ of the button.  For general use, this is not an issue.  See the Advanced Configu | |
| 190 195 | 
             
            For anyone needing to handle rendering in a special way, wizardly provides a render
         | 
| 191 196 | 
             
            call back for this.
         | 
| 192 197 |  | 
| 193 | 
            -
              class SignupController <  | 
| 198 | 
            +
              class SignupController < ApplicationController
         | 
| 194 199 | 
             
                act_wizardly_for :user, :redirect=>'/main'
         | 
| 195 200 |  | 
| 196 201 | 
             
                def render_wizard_page
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            require 'wizardly'
         | 
    
        data/lib/validation_group.rb
    CHANGED
    
    | @@ -23,13 +23,20 @@ module ValidationGroup | |
| 23 23 |  | 
| 24 24 | 
             
                  def validation_group(name, options={})
         | 
| 25 25 | 
             
                    self_groups = (self.validation_group_classes[self] ||= {})
         | 
| 26 | 
            -
                    self_groups[name.to_sym] = options[:fields] | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 26 | 
            +
                    self_groups[name.to_sym] = case options[:fields]
         | 
| 27 | 
            +
            				when Array then options[:fields]
         | 
| 28 | 
            +
            				when Symbol, String then [options[:fields].to_sym]
         | 
| 29 | 
            +
            				else []
         | 
| 30 | 
            +
            				end
         | 
| 31 | 
            +
                    # jeffp: capture the declaration order for this class only (no
         | 
| 32 | 
            +
                    # superclasses)
         | 
| 33 | 
            +
                    (@validation_group_order ||= []) << name.to_sym
         | 
| 29 34 |  | 
| 30 35 | 
             
                    unless included_modules.include?(InstanceMethods)
         | 
| 36 | 
            +
                      # jeffp: added reader for current_validation_fields
         | 
| 31 37 | 
             
                      attr_reader :current_validation_group, :current_validation_fields
         | 
| 32 38 | 
             
                      include InstanceMethods
         | 
| 39 | 
            +
                      # jeffp: add valid?(group = nil), see definition below
         | 
| 33 40 | 
             
                      alias_method_chain :valid?, :validation_group
         | 
| 34 41 | 
             
                    end
         | 
| 35 42 | 
             
                  end
         | 
| @@ -47,6 +54,7 @@ module ValidationGroup | |
| 47 54 | 
             
                    end
         | 
| 48 55 | 
             
                    if found
         | 
| 49 56 | 
             
                      @current_validation_group = group
         | 
| 57 | 
            +
                      # jeffp: capture current fields for performance optimization
         | 
| 50 58 | 
             
                      @current_validation_fields = group_classes[found][group]
         | 
| 51 59 | 
             
                    else
         | 
| 52 60 | 
             
                      raise ArgumentError, "No validation group of name :#{group}"
         | 
| @@ -55,9 +63,13 @@ module ValidationGroup | |
| 55 63 |  | 
| 56 64 | 
             
                  def disable_validation_group
         | 
| 57 65 | 
             
                    @current_validation_group = nil
         | 
| 66 | 
            +
                    # jeffp: delete fields
         | 
| 58 67 | 
             
                    @current_validation_fields = nil
         | 
| 59 68 | 
             
                  end
         | 
| 60 69 |  | 
| 70 | 
            +
                  # jeffp: optimizer for someone writing custom :validate method -- no need
         | 
| 71 | 
            +
                  # to validate fields outside the current validation group note: could also
         | 
| 72 | 
            +
                  # use in validation modules to improve performance
         | 
| 61 73 | 
             
                  def should_validate?(attribute)
         | 
| 62 74 | 
             
            	!self.validation_group_enabled? || (@current_validation_fields && @current_validation_fields.include?(attribute.to_sym))
         | 
| 63 75 | 
             
                  end
         | 
| @@ -78,6 +90,7 @@ module ValidationGroup | |
| 78 90 | 
             
                  def add_with_validation_group(attribute,
         | 
| 79 91 | 
             
                      msg = @@default_error_messages[:invalid], *args,
         | 
| 80 92 | 
             
                      &block)
         | 
| 93 | 
            +
                    # jeffp: setting @current_validation_fields and use of should_validate? optimizes code
         | 
| 81 94 | 
             
                    add_error = @base.respond_to?(:should_validate?) ? @base.should_validate?(attribute.to_sym) : true
         | 
| 82 95 | 
             
                    add_without_validation_group(attribute, msg, *args, &block) if add_error
         | 
| 83 96 | 
             
                  end
         | 
| @@ -106,5 +119,7 @@ module ValidationGroup | |
| 106 119 | 
             
              end
         | 
| 107 120 | 
             
            end
         | 
| 108 121 |  | 
| 122 | 
            +
            # jeffp:  moved from init.rb for gemification purposes -- 
         | 
| 123 | 
            +
            # require 'validation_group' loads everything now, init.rb requires 'validation_group' only
         | 
| 109 124 | 
             
            ActiveRecord::Base.send(:extend, ValidationGroup::ActiveRecord::ActsMethods)
         | 
| 110 125 | 
             
            ActiveRecord::Errors.send :include, ValidationGroup::ActiveRecord::Errors
         | 
| @@ -20,7 +20,6 @@ module Wizardly | |
| 20 20 |  | 
| 21 21 | 
             
                    # controller_name = self.name.sub(/Controller$/, '').underscore.to_sym
         | 
| 22 22 | 
             
                    @wizard_config = Wizardly::Wizard::Configuration.create(controller_name, model, opts, &block)
         | 
| 23 | 
            -
             | 
| 24 23 | 
             
                    # define methods
         | 
| 25 24 | 
             
                    self.class_eval @wizard_config.print_page_action_methods
         | 
| 26 25 | 
             
                    self.class_eval @wizard_config.print_callbacks
         | 
    
        data/lib/wizardly/wizard.rb
    CHANGED
    
    | @@ -4,6 +4,7 @@ module Wizardly | |
| 4 4 | 
             
              class WizardlyError < StandardError; end
         | 
| 5 5 | 
             
              class ModelNotFoundError < WizardlyError; end
         | 
| 6 6 | 
             
              class ValidationGroupError < WizardlyError; end
         | 
| 7 | 
            +
              class CallbackError < WizardlyError; end
         | 
| 7 8 | 
             
              class MissingCallbackError < WizardlyError; end
         | 
| 8 9 | 
             
              class WizardConfigurationError < WizardlyError; end
         | 
| 9 10 | 
             
              class RedirectNotDefinedError < WizardlyError; end
         | 
| @@ -14,6 +14,7 @@ module Wizardly | |
| 14 14 | 
             
                    @completed_redirect = opts[:redirect] || opts[:completed] || opts[:when_completed] #format_redirect(completed_redirect)
         | 
| 15 15 | 
             
                    @canceled_redirect = opts[:redirect] || opts[:canceled] || opts[:when_canceled]
         | 
| 16 16 | 
             
                    @allow_skipping = opts[:skip] || opts[:allow_skip] || opts[:allow_skipping] || false
         | 
| 17 | 
            +
                    @guard = opts.key?(:guard) ? opts[:guard] : true        
         | 
| 17 18 | 
             
                    @password_fields = opts[:mask_fields] || opts[:mask_passwords] || [:password, :password_confirmation]
         | 
| 18 19 | 
             
                    @page_order = []
         | 
| 19 20 | 
             
                    @pages = {}
         | 
| @@ -23,7 +24,8 @@ module Wizardly | |
| 23 24 | 
             
                      @default_buttons[default] = Button.new(default)
         | 
| 24 25 | 
             
                    end
         | 
| 25 26 | 
             
                  end
         | 
| 26 | 
            -
             | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def guard?; @guard; end
         | 
| 27 29 | 
             
                  def model; @wizard_model_sym; end
         | 
| 28 30 | 
             
                  def model_instance_variable; "@#{@wizard_model_sym.to_s}"; end
         | 
| 29 31 | 
             
                  def model_class_name; @wizard_model_class_name; end
         | 
| @@ -67,18 +69,24 @@ module Wizardly | |
| 67 69 | 
             
                    begin
         | 
| 68 70 | 
             
                      @page_order = @wizard_model_const.validation_group_order 
         | 
| 69 71 | 
             
                    rescue Exception => e
         | 
| 70 | 
            -
                      raise ValidationGroupError, " | 
| 72 | 
            +
                      raise ValidationGroupError, "Unable to read validation groups from #{@wizard_model_class_name}: " + e.message, caller
         | 
| 71 73 | 
             
                    end
         | 
| 72 74 | 
             
                    raise(ValidationGroupError, "No validation groups defined for model #{@wizard_model_class_name}", caller) unless (@page_order && !@page_order.empty?)
         | 
| 73 75 |  | 
| 74 76 | 
             
                    begin
         | 
| 75 77 | 
             
                      groups = @wizard_model_const.validation_groups
         | 
| 78 | 
            +
                      enum_attrs = @wizard_model_const.respond_to?(:enumerated_attributes) ? @wizard_model_const.enumerated_attributes.collect {|k,v| k } : []
         | 
| 76 79 | 
             
                      model_inst = @wizard_model_const.new
         | 
| 77 80 | 
             
                      last_index = @page_order.size-1
         | 
| 78 81 | 
             
                      @page_order.each_with_index do |p, index|
         | 
| 79 82 | 
             
                        fields = groups[p].map do |f|
         | 
| 80 83 | 
             
                          column = model_inst.column_for_attribute(f)
         | 
| 81 | 
            -
                          type =  | 
| 84 | 
            +
                          type = case
         | 
| 85 | 
            +
                          when enum_attrs.include?(f) then :enum
         | 
| 86 | 
            +
                          when (@password_fields && @password_fields.include?(f)) then :password
         | 
| 87 | 
            +
                          else
         | 
| 88 | 
            +
                            column ? column.type : :string
         | 
| 89 | 
            +
                          end
         | 
| 82 90 | 
             
                          PageField.new(f, type)
         | 
| 83 91 | 
             
                        end
         | 
| 84 92 | 
             
                        page = Page.new(p, fields)
         | 
| @@ -25,52 +25,70 @@ module Wizardly | |
| 25 25 | 
             
                    next_button = self.button_for_function(:next).id
         | 
| 26 26 | 
             
                    (mb = StringIO.new) << <<-ONE
         | 
| 27 27 | 
             
              def #{page.name}
         | 
| 28 | 
            -
                 | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
                   | 
| 39 | 
            -
                   | 
| 40 | 
            -
                   | 
| 41 | 
            -
             | 
| 28 | 
            +
                begin
         | 
| 29 | 
            +
                  @step = :#{id}
         | 
| 30 | 
            +
                  @wizard = wizard_config
         | 
| 31 | 
            +
                  @title = '#{page.title}'
         | 
| 32 | 
            +
                  @description = '#{page.description}'
         | 
| 33 | 
            +
                  h = (flash[:wizard_model]||{}).merge(params[:#{self.model}] || {}) 
         | 
| 34 | 
            +
                  @#{self.model} = #{self.model_class_name}.new(h)
         | 
| 35 | 
            +
                  if request.post? && callback_performs_action?(:on_post_#{id}_form)
         | 
| 36 | 
            +
                    raise CallbackError, "render or redirect not allowed in :filter_params_#{id}_page callback", caller
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                  button_id = check_action_for_button
         | 
| 39 | 
            +
                  return if performed?
         | 
| 40 | 
            +
                  if request.get?
         | 
| 41 | 
            +
                    return if callback_performs_action?(:on_get_#{id}_form)
         | 
| 42 | 
            +
                    render_wizard_form
         | 
| 43 | 
            +
                    return
         | 
| 44 | 
            +
                  end
         | 
| 42 45 |  | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 46 | 
            +
                  # @#{self.model}.enable_validation_group :#{id}
         | 
| 47 | 
            +
                  unless @#{self.model}.valid?(:#{id})
         | 
| 48 | 
            +
                    return if callback_performs_action?(:on_invalid_#{id}_form)
         | 
| 49 | 
            +
                    render_wizard_form
         | 
| 50 | 
            +
                    return
         | 
| 51 | 
            +
                  end
         | 
| 49 52 |  | 
| 50 53 | 
             
                    ONE
         | 
| 51 54 | 
             
                    if self.last_page?(id)
         | 
| 52 55 | 
             
                      mb << <<-TWO
         | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            +
                  return if callback_performs_action?(:on_#{id}_form_#{finish_button})
         | 
| 57 | 
            +
                  _on_wizard_#{finish_button}
         | 
| 58 | 
            +
                  redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed?
         | 
| 56 59 | 
             
                    TWO
         | 
| 57 60 | 
             
                    elsif self.first_page?(id)
         | 
| 58 61 | 
             
                      mb << <<-THREE
         | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 62 | 
            +
                  if button_id == :#{finish_button}
         | 
| 63 | 
            +
                    return if callback_performs_action?(:on_#{id}_form_#{finish_button})
         | 
| 64 | 
            +
                    _on_wizard_#{finish_button} if button_id == :#{finish_button}
         | 
| 65 | 
            +
                    redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed?
         | 
| 66 | 
            +
                    return
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                  session[:progression] = [:#{id}]
         | 
| 69 | 
            +
                  return if callback_performs_action?(:on_#{id}_form_#{next_button})
         | 
| 70 | 
            +
                  redirect_to :action=>:#{self.next_page(id)}
         | 
| 64 71 | 
             
                    THREE
         | 
| 65 72 | 
             
                    else
         | 
| 66 73 | 
             
                      mb << <<-FOUR
         | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 74 | 
            +
                  if button_id == :#{finish_button}
         | 
| 75 | 
            +
                    return if callback_performs_action?(:on_#{id}_form_#{finish_button})
         | 
| 76 | 
            +
                    _on_wizard_#{finish_button} if button_id == :#{finish_button}
         | 
| 77 | 
            +
                    redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed?
         | 
| 78 | 
            +
                    return
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                  session[:progression].push(:#{id})
         | 
| 81 | 
            +
                  return if callback_performs_action?(:on_#{id}_form_#{next_button})
         | 
| 82 | 
            +
                  redirect_to :action=>:#{self.next_page(id)}
         | 
| 72 83 | 
             
                    FOUR
         | 
| 73 84 | 
             
                    end
         | 
| 85 | 
            +
                    
         | 
| 86 | 
            +
                    mb << <<-ENSURE
         | 
| 87 | 
            +
                ensure
         | 
| 88 | 
            +
                  flash[:wizard_model] = h.merge(@#{self.model}.attributes)    
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end        
         | 
| 91 | 
            +
            ENSURE
         | 
| 74 92 | 
             
                    mb.string
         | 
| 75 93 | 
             
                  end
         | 
| 76 94 |  | 
| @@ -83,26 +101,26 @@ module Wizardly | |
| 83 101 | 
             
              protected
         | 
| 84 102 | 
             
              def _on_wizard_#{finish}
         | 
| 85 103 | 
             
                @#{self.model}.save_without_validation!
         | 
| 86 | 
            -
                flash.discard(:wizard_model)
         | 
| 87 104 | 
             
                _wizard_final_redirect_to(:completed)
         | 
| 88 105 | 
             
              end
         | 
| 89 106 | 
             
              def _on_wizard_#{skip}
         | 
| 90 | 
            -
                redirect_to | 
| 91 | 
            -
                true
         | 
| 107 | 
            +
                redirect_to(:action=>wizard_config.next_page(@step)) unless self.performed?
         | 
| 92 108 | 
             
              end
         | 
| 93 109 | 
             
              def _on_wizard_#{back}
         | 
| 94 | 
            -
                 | 
| 95 | 
            -
                 | 
| 110 | 
            +
                # TODO: fix progression management
         | 
| 111 | 
            +
                redirect_to(:action=>((session[:progression]||[]).pop || :#{self.page_order.first})) unless self.performed?
         | 
| 96 112 | 
             
              end
         | 
| 97 113 | 
             
              def _on_wizard_#{cancel}
         | 
| 98 114 | 
             
                _wizard_final_redirect_to(:canceled)
         | 
| 99 | 
            -
                true
         | 
| 100 115 | 
             
              end
         | 
| 101 116 | 
             
              def _wizard_final_redirect_to(which_redirect) 
         | 
| 117 | 
            +
                flash.discard(:wizard_model)
         | 
| 102 118 | 
             
                initial_referer = reset_wizard_session_vars
         | 
| 103 | 
            -
                 | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 119 | 
            +
                unless self.performed?
         | 
| 120 | 
            +
                  redir = (which_redirect == :completed ? wizard_config.completed_redirect : wizard_config.canceled_redirect) || initial_referer
         | 
| 121 | 
            +
                  return redirect_to(redir) if redir
         | 
| 122 | 
            +
                  raise Wizardly::RedirectNotDefinedError, "No redirect was defined for completion or canceling the wizard.  Use :completed and :canceled options to define redirects.", caller
         | 
| 123 | 
            +
                end
         | 
| 106 124 | 
             
              end
         | 
| 107 125 | 
             
              hide_action :_on_wizard_#{finish}, :_on_wizard_#{skip}, :_on_wizard_#{back}, :_on_wizard_#{cancel}, :_wizard_final_redirect_to
         | 
| 108 126 | 
             
                  CALLBACKS
         | 
| @@ -112,6 +130,7 @@ module Wizardly | |
| 112 130 | 
             
                    next_id = self.button_for_function(:next).id
         | 
| 113 131 | 
             
                    finish_id = self.button_for_function(:finish).id
         | 
| 114 132 | 
             
                    first_page = self.page_order.first
         | 
| 133 | 
            +
                    guard_line = self.guard? ? '' : 'return #guard entry disabled'
         | 
| 115 134 | 
             
                  <<-HELPERS
         | 
| 116 135 | 
             
              protected
         | 
| 117 136 | 
             
              def guard_entry
         | 
| @@ -123,13 +142,14 @@ module Wizardly | |
| 123 142 | 
             
                  session[:initial_referer] = nil
         | 
| 124 143 | 
             
                end
         | 
| 125 144 | 
             
                flash.discard(:wizard_model)
         | 
| 145 | 
            +
                #{guard_line}
         | 
| 126 146 | 
             
                redirect_to :action=>:#{first_page} unless (params[:action] || '') == '#{first_page}'
         | 
| 127 147 | 
             
              end   
         | 
| 128 148 | 
             
              hide_action :guard_entry
         | 
| 129 149 |  | 
| 130 | 
            -
              def  | 
| 150 | 
            +
              def render_wizard_form
         | 
| 131 151 | 
             
              end
         | 
| 132 | 
            -
              hide_action : | 
| 152 | 
            +
              hide_action :render_wizard_form
         | 
| 133 153 |  | 
| 134 154 | 
             
              def performed?; super; end
         | 
| 135 155 | 
             
              hide_action :performed?
         | 
| @@ -140,14 +160,13 @@ module Wizardly | |
| 140 160 | 
             
                unless (params[:commit] == nil)
         | 
| 141 161 | 
             
                  button_name = methodize_button_name(params[:commit])
         | 
| 142 162 | 
             
                  unless [:#{next_id}, :#{finish_id}].include?(button_id = button_name.to_sym)
         | 
| 143 | 
            -
                    action_method_name = "on_" + params[:action].to_s + " | 
| 144 | 
            -
                     | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 150 | 
            -
                      end
         | 
| 163 | 
            +
                    action_method_name = "on_" + params[:action].to_s + "_form_" + button_name
         | 
| 164 | 
            +
                    callback_performs_action?(action_method_name)
         | 
| 165 | 
            +
                    method_name = "_on_wizard_" + button_name
         | 
| 166 | 
            +
                    if (self.method(method_name))
         | 
| 167 | 
            +
                      self.__send__(method_name)
         | 
| 168 | 
            +
                    else
         | 
| 169 | 
            +
                      raise MissingCallbackError, "Callback method either '" + action_method_name + "' or '" + method_name + "' not defined", caller
         | 
| 151 170 | 
             
                    end
         | 
| 152 171 | 
             
                  end
         | 
| 153 172 | 
             
                end
         | 
| @@ -161,22 +180,12 @@ module Wizardly | |
| 161 180 | 
             
                attr_reader :wizard_callbacks
         | 
| 162 181 | 
             
              end
         | 
| 163 182 |  | 
| 164 | 
            -
              def callback_performs_action?(methId)
         | 
| 165 | 
            -
                 | 
| 166 | 
            -
                 | 
| 167 | 
            -
                 | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
                else #nil
         | 
| 171 | 
            -
                  unless self.class.method_defined?(methId)
         | 
| 172 | 
            -
                    wc[methId] = :none
         | 
| 173 | 
            -
                    return false
         | 
| 174 | 
            -
                  end
         | 
| 175 | 
            -
                  wc[methId] = :found
         | 
| 176 | 
            -
                end
         | 
| 177 | 
            -
                self.__send__(methId)
         | 
| 178 | 
            -
                return self.performed?
         | 
| 179 | 
            -
              end    
         | 
| 183 | 
            +
              def callback_performs_action?(methId, arg=nil)
         | 
| 184 | 
            +
                return false unless self.methods.include?(methId.to_s)
         | 
| 185 | 
            +
                #self.__send__(methId)
         | 
| 186 | 
            +
                self.method(methId).call
         | 
| 187 | 
            +
                self.performed?
         | 
| 188 | 
            +
              end
         | 
| 180 189 | 
             
              hide_action :callback_performs_action?
         | 
| 181 190 |  | 
| 182 191 | 
             
                  HELPERS
         | 
    
        data/lib/wizardly/wizard/page.rb
    CHANGED
    
    | @@ -43,6 +43,7 @@ module Wizardly | |
| 43 43 | 
             
                    @field_type ||= case @column_type
         | 
| 44 44 | 
             
                    when :string                      then :text_field
         | 
| 45 45 | 
             
                    when :password                    then :password_field
         | 
| 46 | 
            +
                    when :enum                        then :enum_select
         | 
| 46 47 | 
             
                    when :text                        then :text_area
         | 
| 47 48 | 
             
                    when :boolean                     then :check_box
         | 
| 48 49 | 
             
                    when :integer, :float, :decimal   then :text_field
         | 
| @@ -14,14 +14,18 @@ namespace :wizardly do | |
| 14 14 | 
             
                      puts
         | 
| 15 15 | 
             
                      puts c.print_config
         | 
| 16 16 | 
             
                    rescue Exception=>e
         | 
| 17 | 
            -
                      puts "Problem printing configuration | 
| 17 | 
            +
                      puts "Problem printing configuration."
         | 
| 18 | 
            +
                      puts "#{e.class.name} -- #{e.message}"
         | 
| 19 | 
            +
                      puts
         | 
| 18 20 | 
             
                    end
         | 
| 19 | 
            -
                  rescue
         | 
| 20 | 
            -
                    puts "{#{name}} is not a 'wizardly' controller.\nMake sure 'wizard_for_model' is defined in the controller class."
         | 
| 21 | 
            +
                  rescue Exception=>e
         | 
| 22 | 
            +
                    puts "{#{name}} is not a 'wizardly' controller.\nMake sure 'wizard_for_model' is defined in the controller class." 
         | 
| 23 | 
            +
                    puts "#{e.class.name} -- #{e.message}"
         | 
| 21 24 | 
             
                    puts
         | 
| 22 25 | 
             
                  end
         | 
| 23 | 
            -
                rescue
         | 
| 24 | 
            -
                  puts "{#{name}} does not reference a controller class"
         | 
| 26 | 
            +
                rescue Exception=>e
         | 
| 27 | 
            +
                  puts "{#{name}} does not reference a controller class."
         | 
| 28 | 
            +
                  puts "#{e.class.name} -- #{e.message}"
         | 
| 25 29 | 
             
                  puts
         | 
| 26 30 | 
             
                end
         | 
| 27 31 | 
             
              end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            %h1 <%= page.title %>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <% unless page.description.blank? %>
         | 
| 4 | 
            +
              %p <%= page.description %>
         | 
| 5 | 
            +
            <% end %>
         | 
| 6 | 
            +
            - if flash[:notice]
         | 
| 7 | 
            +
              %p{:style=>'color: green'}= flash[:notice]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            - form_for :<%= model_name %>, :url=>{:action=>:<%= page.name %>} do |f|
         | 
| 10 | 
            +
              = f.error_messages
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
            <% for field in page.fields %>
         | 
| 13 | 
            +
              <% first_field_id ||= "#{model_name}_#{field.name}" %>
         | 
| 14 | 
            +
              %p
         | 
| 15 | 
            +
                = f.label :<%= field.name %>
         | 
| 16 | 
            +
                %br
         | 
| 17 | 
            +
                = f.<%= field.field_type %> :<%= field.name %>
         | 
| 18 | 
            +
            <% end %>
         | 
| 19 | 
            +
              %p= wizardly_submit
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            %script{:type=>'text/javascript'} 
         | 
| 22 | 
            +
              document.getElementById('<%=first_field_id %>').focus()
         | 
| @@ -0,0 +1,10 @@ | |
| 1 | 
            +
            !!! XML
         | 
| 2 | 
            +
            !!!
         | 
| 3 | 
            +
            %html{ :'xml:lang' => "en", :lang => "en" }
         | 
| 4 | 
            +
              %head
         | 
| 5 | 
            +
                %title= "<%=controller_class_name %>: " + controller.action_name
         | 
| 6 | 
            +
                %meta{ :"http-equiv" => "Content-Type", :content => "text/html; charset-utf-8" }
         | 
| 7 | 
            +
                %link{ :rel => "shortcut icon", :href => "/favicon.ico" }
         | 
| 8 | 
            +
                = stylesheet_link_tag "scaffold", :media => "screen"
         | 
| 9 | 
            +
              %body
         | 
| 10 | 
            +
                = yield
         | 
| @@ -13,10 +13,16 @@ class WizardlyScaffoldGenerator < Rails::Generator::Base | |
| 13 13 |  | 
| 14 14 | 
             
              alias_method :controller_file_name, :controller_underscore_name
         | 
| 15 15 |  | 
| 16 | 
            +
              def add_options!(opt)
         | 
| 17 | 
            +
                opt.on('--haml', 'Generate scaffold for haml wizard') { |v| options[:output] = :haml }
         | 
| 18 | 
            +
                opt.on('--ajax', 'Generate scaffold for ajax wizard') { |v| options[:output] = :ajax }
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
              
         | 
| 21 | 
            +
              
         | 
| 16 22 | 
             
              def initialize(runtime_args, runtime_options = {})
         | 
| 17 23 | 
             
                super
         | 
| 18 24 | 
             
                name = @args[0].sub(/^:/, '').underscore.sub(/_controller$/, '').camelize + 'Controller'
         | 
| 19 | 
            -
             | 
| 25 | 
            +
             | 
| 20 26 | 
             
                base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(name)
         | 
| 21 27 | 
             
                @controller_class_name_without_nesting = base_name.camelize
         | 
| 22 28 | 
             
                @controller_underscore_name = base_name.underscore
         | 
| @@ -26,7 +32,7 @@ class WizardlyScaffoldGenerator < Rails::Generator::Base | |
| 26 32 | 
             
                else
         | 
| 27 33 | 
             
                  @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
         | 
| 28 34 | 
             
                end
         | 
| 29 | 
            -
             | 
| 35 | 
            +
             | 
| 30 36 | 
             
                begin
         | 
| 31 37 | 
             
                  @controller_class = @controller_class_name.constantize 
         | 
| 32 38 | 
             
                rescue Exception => e
         | 
| @@ -34,15 +40,17 @@ class WizardlyScaffoldGenerator < Rails::Generator::Base | |
| 34 40 | 
             
                end
         | 
| 35 41 | 
             
                begin
         | 
| 36 42 | 
             
                  @wizard_config = @controller_class.wizard_config
         | 
| 37 | 
            -
                rescue
         | 
| 38 | 
            -
                  raise Wizardly::WizardlyScaffoldError, "#{@controller_class_name} must  | 
| 43 | 
            +
                rescue Exception => e
         | 
| 44 | 
            +
                  raise Wizardly::WizardlyScaffoldError, "#{@controller_class_name} must contain a valid 'act_wizardly_for' or 'wizard_for_model' macro: " + e.message, caller
         | 
| 39 45 | 
             
                end
         | 
| 40 | 
            -
             | 
| 46 | 
            +
             | 
| 41 47 | 
             
                @pages = @wizard_config.pages
         | 
| 42 48 | 
             
                @model_name = @wizard_config.model
         | 
| 43 | 
            -
             | 
| 49 | 
            +
             | 
| 44 50 | 
             
                #based on options, default is --html, others --ajax, --haml
         | 
| 45 | 
            -
                @view_file_ext = "html.erb"
         | 
| 51 | 
            +
                @view_file_ext = ["html.erb", "html.erb"]
         | 
| 52 | 
            +
                @view_file_ext = ["html.haml.erb", "html.haml"] if options[:output] == :haml
         | 
| 53 | 
            +
                #ajax
         | 
| 46 54 | 
             
              end
         | 
| 47 55 |  | 
| 48 56 | 
             
              def manifest
         | 
| @@ -56,8 +64,8 @@ class WizardlyScaffoldGenerator < Rails::Generator::Base | |
| 56 64 |  | 
| 57 65 | 
             
                  pages.each do |id, page|
         | 
| 58 66 | 
             
                    m.template(
         | 
| 59 | 
            -
                      "form.#{view_file_ext}",
         | 
| 60 | 
            -
                      File.join('app/views', controller_class_path, controller_name, "#{id}.#{view_file_ext}"),
         | 
| 67 | 
            +
                      "form.#{view_file_ext.first}",
         | 
| 68 | 
            +
                      File.join('app/views', controller_class_path, controller_name, "#{id}.#{view_file_ext.last}"),
         | 
| 61 69 | 
             
                      :assigns=>{:id=>id, :page=>page}
         | 
| 62 70 | 
             
                    )
         | 
| 63 71 | 
             
                  end
         | 
| @@ -65,7 +73,7 @@ class WizardlyScaffoldGenerator < Rails::Generator::Base | |
| 65 73 | 
             
                  m.template("helper.rb.erb", File.join('app/helpers', controller_class_path, "#{controller_name}_helper.rb"))
         | 
| 66 74 |  | 
| 67 75 | 
             
                  # Layout and stylesheet.
         | 
| 68 | 
            -
                  m.template("layout.#{view_file_ext}", File.join('app/views/layouts', controller_class_path, "#{controller_name}.#{view_file_ext}"))
         | 
| 76 | 
            +
                  m.template("layout.#{view_file_ext.first}", File.join('app/views/layouts', controller_class_path, "#{controller_name}.#{view_file_ext.last}"))
         | 
| 69 77 | 
             
                  m.template('style.css', 'public/stylesheets/scaffold.css')
         | 
| 70 78 |  | 
| 71 79 | 
             
                  #m.dependency 'model', [name] + @args, :collision => :skip
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: jeffp-wizardly
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 0.1. | 
| 4 | 
            +
              version: 0.1.6
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - Jeff Patmon
         | 
| @@ -9,7 +9,7 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 11 |  | 
| 12 | 
            -
            date: 2009-08- | 
| 12 | 
            +
            date: 2009-08-10 00:00:00 -07:00
         | 
| 13 13 | 
             
            default_executable: 
         | 
| 14 14 | 
             
            dependencies: []
         | 
| 15 15 |  | 
| @@ -23,6 +23,7 @@ extra_rdoc_files: [] | |
| 23 23 |  | 
| 24 24 | 
             
            files: 
         | 
| 25 25 | 
             
            - lib/generators
         | 
| 26 | 
            +
            - lib/jeffp-wizardly.rb
         | 
| 26 27 | 
             
            - lib/validation_group.rb
         | 
| 27 28 | 
             
            - lib/wizardly
         | 
| 28 29 | 
             
            - lib/wizardly/action_controller.rb
         | 
| @@ -51,8 +52,10 @@ files: | |
| 51 52 | 
             
            - rails_generators/wizardly_scaffold
         | 
| 52 53 | 
             
            - rails_generators/wizardly_scaffold/templates
         | 
| 53 54 | 
             
            - rails_generators/wizardly_scaffold/templates/form.html.erb
         | 
| 55 | 
            +
            - rails_generators/wizardly_scaffold/templates/form.html.haml.erb
         | 
| 54 56 | 
             
            - rails_generators/wizardly_scaffold/templates/helper.rb.erb
         | 
| 55 57 | 
             
            - rails_generators/wizardly_scaffold/templates/layout.html.erb
         | 
| 58 | 
            +
            - rails_generators/wizardly_scaffold/templates/layout.html.haml.erb
         | 
| 56 59 | 
             
            - rails_generators/wizardly_scaffold/templates/style.css
         | 
| 57 60 | 
             
            - rails_generators/wizardly_scaffold/USAGE
         | 
| 58 61 | 
             
            - rails_generators/wizardly_scaffold/wizardly_scaffold_generator.rb
         |