wizardry 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -6,12 +6,84 @@ Simple step-by-step wizard for Rails.
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
- gem 'wizardry'
9
+ ```ruby
10
+ gem 'wizardry'
11
+ ```
10
12
 
11
- And then execute:
12
-
13
- $ bundle
13
+ And run the `bundle` command to install it.
14
14
 
15
15
  ## Usage
16
16
 
17
- TODO: Write usage instructions here
17
+ Bring wizardry to your model:
18
+
19
+ ```ruby
20
+ class Product < ActiveRecord::Base
21
+ wizardry :initial, :middle, :final
22
+ end
23
+ ```
24
+
25
+ And you will get a bunch of methods.
26
+ To get name of the current step:
27
+
28
+ ```ruby
29
+ @product.current_step # => 'initial'
30
+ ```
31
+
32
+ To change the current step name:
33
+
34
+ ```ruby
35
+ @product.current_step = :middle
36
+ ```
37
+
38
+ Will be set only if new step name is included in wizardry steps (**initial**, **middle**, **final** in our example).
39
+
40
+ For the second step name:
41
+
42
+ ```ruby
43
+ @product.second_step # => 'middle'
44
+ ```
45
+
46
+ Also `first_step`, `third_step`, etc. methods are available.
47
+
48
+ You can check position of the current step:
49
+
50
+ ```ruby
51
+ @product.second_step? # => true
52
+ # or
53
+ @product.current_step.middle? # => true
54
+ ```
55
+
56
+ Also `first_step?`, `third_step?`, etc. methods are accessible.
57
+
58
+ To get name of the next and previous steps:
59
+
60
+ ```ruby
61
+ @product.next_step
62
+ # and
63
+ @product.previous_step
64
+ ```
65
+
66
+ If not exists next/previous step then `nil` will be returned.
67
+
68
+ Class methods are accessible:
69
+
70
+ ```ruby
71
+ Product.steps # => ['initial', 'middle', 'final']
72
+ # and
73
+ Product.steps_regexp # => /initial|middle|final/
74
+ ```
75
+
76
+ ### Routing helpers
77
+
78
+ Wizardry includes some routing helpers:
79
+
80
+ ```ruby
81
+ resources :products do
82
+ has_wizardry
83
+ end
84
+ # same as
85
+ wizardry_resources :products
86
+ ```
87
+
88
+ will replace default *:id/edit* path with *:id/edit/:step* (and `:step => /initial|middle|final/` in our example).
89
+ `has_wizardry` is also acceptable for singular resources. And `wizardry_resource` herper is here for that.
data/lib/wizardry.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'wizardry/version'
2
2
  require 'wizardry/base'
3
+ require 'wizardry/routes'
3
4
 
4
5
  module Wizardry
5
- ORDINALS = [:first, :second, :third, :fourth, :fifth, :sixth, :seventh]
6
+ ORDINALS = %w[first second third fourth fifth sixth seventh]
6
7
  end
data/lib/wizardry/base.rb CHANGED
@@ -4,9 +4,10 @@ module Wizardry
4
4
 
5
5
  module ClassMethods
6
6
  def wizardry(*steps)
7
- cattr_accessor :steps, instance_writer: false
7
+ class_attribute :steps, :steps_regexp, instance_writer: false
8
8
 
9
- self.steps = steps
9
+ self.steps = steps.map{ |s| s.to_s.inquiry }
10
+ self.steps_regexp = Regexp.new(steps.join('|'))
10
11
 
11
12
  include WizardryMethods
12
13
 
@@ -30,7 +31,8 @@ module Wizardry
30
31
  end
31
32
 
32
33
  def current_step=(step)
33
- @current_step = step if steps.include?(step)
34
+ step = step.to_s
35
+ @current_step = step.inquiry if steps.include?(step)
34
36
  end
35
37
 
36
38
  def next_step
@@ -0,0 +1,34 @@
1
+ class ActionDispatch::Routing::Mapper
2
+ def has_wizardry
3
+ unless resource_scope?
4
+ raise ArgumentError, "can't use has_wizardry outside resource(s) scope"
5
+ end
6
+
7
+ options = @scope[:scope_level_resource].options
8
+
9
+ if options.has_key?(:only)
10
+ only = Array.wrap(options.delete(:only))
11
+ only.map!(&:to_sym).delete(:edit)
12
+ options.merge!(only: only) if only.present?
13
+ end
14
+
15
+ except = Array.wrap(options.delete(:except))
16
+ except.map!(&:to_sym) << :edit
17
+ options.merge!(except: except.uniq)
18
+
19
+ res = @scope[:scope_level_resource].instance_variable_get(:@name)
20
+
21
+ get 'edit/:step' => :edit, step: res.to_s.classify.constantize.steps_regexp, as: :edit, on: :member
22
+ end
23
+
24
+ [:resources, :resource].each do |method|
25
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
26
+ def wizardry_#{method}(*res) # def wizardry_resources(*res)
27
+ #{method} *res do # resources *res do
28
+ has_wizardry # has_wizardry
29
+ yield if block_given? # yield if block_given?
30
+ end # end
31
+ end # end
32
+ EOT
33
+ end
34
+ end
@@ -1,3 +1,3 @@
1
1
  module Wizardry
2
- VERSION = "0.0.1"
2
+ VERSION = '0.0.2'
3
3
  end
@@ -0,0 +1,2 @@
1
+ class ProductsController < ApplicationController
2
+ end
@@ -1,58 +1,6 @@
1
1
  Dummy::Application.routes.draw do
2
- # The priority is based upon order of creation:
3
- # first created -> highest priority.
4
-
5
- # Sample of regular route:
6
- # match 'products/:id' => 'catalog#view'
7
- # Keep in mind you can assign values other than :controller and :action
8
-
9
- # Sample of named route:
10
- # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
11
- # This route can be invoked with purchase_url(:id => product.id)
12
-
13
- # Sample resource route (maps HTTP verbs to controller actions automatically):
14
- # resources :products
15
-
16
- # Sample resource route with options:
17
- # resources :products do
18
- # member do
19
- # get 'short'
20
- # post 'toggle'
21
- # end
22
- #
23
- # collection do
24
- # get 'sold'
25
- # end
26
- # end
27
-
28
- # Sample resource route with sub-resources:
29
- # resources :products do
30
- # resources :comments, :sales
31
- # resource :seller
32
- # end
33
-
34
- # Sample resource route with more complex sub-resources
35
- # resources :products do
36
- # resources :comments
37
- # resources :sales do
38
- # get 'recent', :on => :collection
39
- # end
40
- # end
41
-
42
- # Sample resource route within a namespace:
43
- # namespace :admin do
44
- # # Directs /admin/products/* to Admin::ProductsController
45
- # # (app/controllers/admin/products_controller.rb)
46
- # resources :products
47
- # end
48
-
49
- # You can have the root of your site routed with "root"
50
- # just remember to delete public/index.html.
51
- # root :to => 'welcome#index'
52
-
53
- # See how all your routes lay out with "rake routes"
54
-
55
- # This is a legacy wild controller route that's not recommended for RESTful applications.
56
- # Note: This route will make all actions in every controller accessible via GET requests.
57
- # match ':controller(/:action(/:id))(.:format)'
2
+ resources :products, except: :destroy, path_names: { new: :make } do
3
+ get :commit, on: :collection
4
+ has_wizardry
5
+ end
58
6
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,20 @@
1
1
  ENV['RAILS_ENV'] = 'test'
2
2
 
3
- require File.expand_path('../dummy/config/environment.rb', __FILE__)
3
+ require File.expand_path('../dummy/config/environment.rb', __FILE__)
4
4
  require 'minitest/autorun'
5
+ require 'action_controller/test_case'
6
+
7
+ class MiniTest::Spec
8
+ include ActiveSupport::Testing::SetupAndTeardown
9
+ end
10
+
11
+ class RoutingSpec < Minitest::Spec
12
+ include ActionDispatch::Integration::Runner
13
+ include Rails.application.routes.url_helpers
14
+
15
+ before do
16
+ @routes = Rails.application.routes
17
+ end
18
+
19
+ register_spec_type(/Routing/, self)
20
+ end
@@ -7,28 +7,47 @@ describe Wizardry::Base do
7
7
  end
8
8
 
9
9
  it 'must have steps array' do
10
- assert_equal Product.steps, [:initial, :middle, :final]
10
+ assert_equal Product.steps, %w[initial middle final]
11
+ end
12
+
13
+ it 'must have steps regexp' do
14
+ assert_equal Product.steps_regexp, /initial|middle|final/
15
+ end
16
+
17
+ it 'must be instance of StringInquirer class in steps array' do
18
+ assert_equal Product.steps.map{ |s| s.instance_of?(ActiveSupport::StringInquirer) }, [true, true, true]
11
19
  end
12
20
  end
13
21
 
14
22
  describe 'instance methods' do
15
- before :each do
23
+ before do
16
24
  @product = Product.new
17
25
  end
18
26
 
19
27
  it 'must return current step as first step' do
20
- assert_equal @product.current_step, :initial
28
+ assert_equal @product.current_step, 'initial'
21
29
  end
22
30
 
23
- it 'must set current step name' do
31
+ it 'must update current step name with instance of StringInquirer' do
32
+ @product.current_step = 'middle'
33
+ assert_equal @product.current_step, 'middle'
34
+ assert_instance_of ActiveSupport::StringInquirer, @product.current_step
35
+ end
36
+
37
+ it 'must update current step name when symbol is passed' do
24
38
  @product.current_step = :middle
25
- assert_equal @product.current_step, :middle
39
+ assert_equal @product.current_step, 'middle'
40
+ end
41
+
42
+ it 'must not update current step name' do
43
+ @product.current_step = :fictional
44
+ refute_equal @product.current_step, 'fictional'
26
45
  end
27
46
 
28
47
  it 'must have ordinal methods' do
29
- assert_equal @product.first_step, :initial
30
- assert_equal @product.second_step, :middle
31
- assert_equal @product.last_step, :final
48
+ assert_equal @product.first_step, 'initial'
49
+ assert_equal @product.second_step, 'middle'
50
+ assert_equal @product.last_step, 'final'
32
51
 
33
52
  assert @product.first_step?
34
53
  refute @product.second_step?
@@ -42,7 +61,7 @@ describe Wizardry::Base do
42
61
  end
43
62
 
44
63
  it 'must return next step name' do
45
- assert_equal @product.next_step, :middle
64
+ assert_equal @product.next_step, 'middle'
46
65
  end
47
66
 
48
67
  it 'must return `nil` on last step' do
@@ -56,7 +75,7 @@ describe Wizardry::Base do
56
75
 
57
76
  it 'must return previous step name' do
58
77
  @product.current_step = :middle
59
- assert_equal @product.previous_step, :initial
78
+ assert_equal @product.previous_step, 'initial'
60
79
  end
61
80
  end
62
81
  end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Wizardry Routing' do
4
+ it 'must accept wizardry `edit` routes' do
5
+ assert_recognizes({ controller: 'products', action: 'edit', id: '1', step: 'initial'}, '/products/1/edit/initial')
6
+ assert_recognizes({ controller: 'products', action: 'edit', id: '1', step: 'middle'}, '/products/1/edit/middle')
7
+ assert_recognizes({ controller: 'products', action: 'edit', id: '1', step: 'final'}, '/products/1/edit/final')
8
+ assert '/products/1/initial', edit_product_path(id: 1, step: 'initial')
9
+ end
10
+
11
+ it 'must accept only valid steps' do
12
+ assert_raises ActionController::RoutingError do
13
+ assert_recognizes({ controller: 'products', action: 'edit', id: '1', step: 'fictional'}, '/products/1/edit/fictional')
14
+ end
15
+ end
16
+
17
+ it 'must not accept default `edit` route' do
18
+ assert_raises ActionController::RoutingError do
19
+ assert_recognizes({ controller: 'products', action: 'edit', id: '1'}, '/products/1/edit')
20
+ end
21
+ end
22
+
23
+ it 'must not accept `destroy` route' do
24
+ assert_raises ActionController::RoutingError do
25
+ assert_recognizes({ controller: 'products', action: 'destroy', id: '1'}, { path: '/products/1', method: :delete })
26
+ end
27
+ end
28
+
29
+ it 'must accept routes defined in block' do
30
+ assert_recognizes({ controller: 'products', action: 'commit' }, '/products/commit')
31
+ assert '/products/commit', commit_products_path
32
+ end
33
+
34
+ it 'must have overriden `new` path name' do
35
+ assert_recognizes({ controller: 'products', action: 'new' }, '/products/make')
36
+ assert '/products/make', new_product_path
37
+ end
38
+
39
+ it 'must have `wizardry_resources` helper' do
40
+ with_routing do |set|
41
+ set.draw{ wizardry_resources :products }
42
+
43
+ assert_recognizes({ controller: 'products', action: 'edit', id: '1', step: 'initial'}, '/products/1/edit/initial')
44
+ end
45
+ end
46
+
47
+ it 'must have `wizardry_resource` helper' do
48
+ with_routing do |set|
49
+ set.draw{ wizardry_resource :products }
50
+
51
+ assert_recognizes({ controller: 'products', action: 'edit', step: 'initial'}, '/products/edit/initial')
52
+ end
53
+ end
54
+
55
+ it 'must not let to use `has_wizardry` outside resource(s) scope' do
56
+ with_routing do |set|
57
+ assert_raises ArgumentError do
58
+ set.draw{ has_wizardry }
59
+ end
60
+ end
61
+ end
62
+
63
+ it 'must not accept default `edit` route with `only` option' do
64
+ with_routing do |set|
65
+ set.draw{ wizardry_resources :products, only: [:edit, :update] }
66
+
67
+ assert_raises ActionController::RoutingError do
68
+ assert_recognizes({ controller: 'products', action: 'edit', id: '1'}, '/products/1/edit')
69
+ end
70
+ end
71
+ end
72
+ end
data/wizardry.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
 
9
9
  gem.files = `git ls-files`.split($\)
10
10
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
11
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
11
+ gem.test_files = gem.files.grep(%r{^spec/})
12
12
  gem.name = 'wizardry'
13
13
  gem.require_paths = ['lib']
14
14
  gem.version = Wizardry::VERSION
@@ -16,4 +16,5 @@ Gem::Specification.new do |gem|
16
16
  gem.add_dependency 'rails', '~> 3.2'
17
17
 
18
18
  gem.add_development_dependency 'sqlite3'
19
+ gem.add_development_dependency 'minitest'
19
20
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wizardry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-01 00:00:00.000000000 Z
12
+ date: 2012-08-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: minitest
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
46
62
  description: Simple step-by-step wizard for Rails
47
63
  email:
48
64
  - lexmag@gmail.com
@@ -57,11 +73,13 @@ files:
57
73
  - Rakefile
58
74
  - lib/wizardry.rb
59
75
  - lib/wizardry/base.rb
76
+ - lib/wizardry/routes.rb
60
77
  - lib/wizardry/version.rb
61
78
  - spec/dummy/Rakefile
62
79
  - spec/dummy/app/assets/javascripts/application.js
63
80
  - spec/dummy/app/assets/stylesheets/application.css
64
81
  - spec/dummy/app/controllers/application_controller.rb
82
+ - spec/dummy/app/controllers/products_controller.rb
65
83
  - spec/dummy/app/helpers/application_helper.rb
66
84
  - spec/dummy/app/mailers/.gitkeep
67
85
  - spec/dummy/app/models/.gitkeep
@@ -94,6 +112,7 @@ files:
94
112
  - spec/dummy/script/rails
95
113
  - spec/spec_helper.rb
96
114
  - spec/wizardry/base_spec.rb
115
+ - spec/wizardry/routes_spec.rb
97
116
  - wizardry.gemspec
98
117
  homepage: ''
99
118
  licenses: []
@@ -109,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
128
  version: '0'
110
129
  segments:
111
130
  - 0
112
- hash: 3814436817286261879
131
+ hash: -4094284250890369797
113
132
  required_rubygems_version: !ruby/object:Gem::Requirement
114
133
  none: false
115
134
  requirements:
@@ -118,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
137
  version: '0'
119
138
  segments:
120
139
  - 0
121
- hash: 3814436817286261879
140
+ hash: -4094284250890369797
122
141
  requirements: []
123
142
  rubyforge_project:
124
143
  rubygems_version: 1.8.24
@@ -130,6 +149,7 @@ test_files:
130
149
  - spec/dummy/app/assets/javascripts/application.js
131
150
  - spec/dummy/app/assets/stylesheets/application.css
132
151
  - spec/dummy/app/controllers/application_controller.rb
152
+ - spec/dummy/app/controllers/products_controller.rb
133
153
  - spec/dummy/app/helpers/application_helper.rb
134
154
  - spec/dummy/app/mailers/.gitkeep
135
155
  - spec/dummy/app/models/.gitkeep
@@ -162,3 +182,4 @@ test_files:
162
182
  - spec/dummy/script/rails
163
183
  - spec/spec_helper.rb
164
184
  - spec/wizardry/base_spec.rb
185
+ - spec/wizardry/routes_spec.rb