simple_controller 0.1.0 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20f1e8a4f6f58fa76e1ee3679e43aae283a7fd4e
4
- data.tar.gz: 43d4c9d22826ae45ad8b8dac49e7a3b8b4de47c6
3
+ metadata.gz: 022feec11ef15f421596afc8ab71a0f69dd271ed
4
+ data.tar.gz: e048c155d5ad1b659a0a5dd45eada31a64f46916
5
5
  SHA512:
6
- metadata.gz: a11908aca45ebbfa600a58167c38b1cbbc6d84983bee759f3c0120fcbac25c716e2ce8450d2553edb69321389be53b871802d842148c4e077ec87a7dffd516a6
7
- data.tar.gz: 0af55254de294c9d72731feedb60f05f455982e14839f7943b5a794fe7dd4b607b5c5c39c741dc08a7efd4d10c49fefc6493fcce1ed1d6a55d3d4f5c39c944de
6
+ metadata.gz: 52542cc33f334c554d80e15dbb635993c2562e77b3ea3d7536ddd8ec2be80c28105e5cabd0e9d5774717965cdd78c1d7a4e20168e07d1518d847454336cdbf55
7
+ data.tar.gz: eb967704ba637c82038b0ce0611fe8eecdf07d50320dead670c0123f9c7b4f53f4da0a3b10b71617e4d834350b5cf84207f11facffbf19b31a4a859ffac9acc9
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ /.idea/*
data/README.md CHANGED
@@ -39,4 +39,41 @@ UserController.new.call(:touch, user_id: 1) # => same as above
39
39
  It works like a Rails Controller, but has only has the following features:
40
40
  - Callbacks
41
41
  - `params`
42
- - `action_name`
42
+ - `action_name`
43
+
44
+ ## Router
45
+ A router is provided to decouple controller classes from identifiers.
46
+
47
+ ```ruby
48
+ class Router < SimpleController::Router
49
+ end
50
+
51
+ # Router.instance is a singleton for ease of use
52
+ Router.instance.draw do
53
+ match "threes/multiply"
54
+ match "threes/dividing" => "threes#divide"
55
+
56
+ controller :threes do
57
+ match :add
58
+ match subtracting: "subtract"
59
+ end
60
+ # custom syntax
61
+ controller :threes, actions: %i[power]
62
+
63
+ namespace :some_namespace do
64
+ match :magic
65
+ end
66
+
67
+ # no other Rails-like syntax is available
68
+ end
69
+
70
+ Router.call("threes/multiply", number: 6) # calls ThreesController.call(:multiply, number: 6)
71
+ Router.instance.call("threes/multiply", number: 6) # same as above
72
+ ```
73
+
74
+ To custom namespace the controller:
75
+ ```ruby
76
+ Router.instance.parse_controller_name {|controller_name| "#{controller_name}_suffix_controller".classify.constantize }
77
+
78
+ Router.call("threes/multiply", number: 6) # calls ThreesSuffixController.call(:multiply, number: 6)
79
+ ```
@@ -0,0 +1,190 @@
1
+ # based on: https://github.com/rails/rails/blob/d2876141d08341ec67cf6a11a073d1acfb920de7/actionpack/lib/abstract_controller/callbacks.rb
2
+ module SimpleController
3
+ class Base
4
+ module Callbacks
5
+ extend ActiveSupport::Concern
6
+
7
+ # Uses ActiveSupport::Callbacks as the base functionality. For
8
+ # more details on the whole callback system, read the documentation
9
+ # for ActiveSupport::Callbacks.
10
+ include ActiveSupport::Callbacks
11
+
12
+ included do
13
+ define_callbacks :call_action
14
+ end
15
+
16
+ # Override SimpleController::Base's call to run the
17
+ # call callbacks around the normal behavior.
18
+ def call_action(*args)
19
+ run_callbacks(:call_action) do
20
+ super
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ # If +:only+ or +:except+ are used, convert the options into the
26
+ # +:if+ and +:unless+ options of ActiveSupport::Callbacks.
27
+ #
28
+ # The basic idea is that <tt>:only => :index</tt> gets converted to
29
+ # <tt>:if => proc {|c| c.action_name == "index" }</tt>.
30
+ #
31
+ # Note that <tt>:only</tt> has priority over <tt>:if</tt> in case they
32
+ # are used together.
33
+ #
34
+ # only: :index, if: -> { true } # the :if option will be ignored.
35
+ #
36
+ # Note that <tt>:if</tt> has priority over <tt>:except</tt> in case they
37
+ # are used together.
38
+ #
39
+ # except: :index, if: -> { true } # the :except option will be ignored.
40
+ #
41
+ # ==== Options
42
+ # * <tt>only</tt> - The callback should be run only for this action
43
+ # * <tt>except</tt> - The callback should be run for all actions except this action
44
+ def _normalize_callback_options(options)
45
+ _normalize_callback_option(options, :only, :if)
46
+ _normalize_callback_option(options, :except, :unless)
47
+ end
48
+
49
+ def _normalize_callback_option(options, from, to) # :nodoc:
50
+ if from = options[from]
51
+ from = Array(from).map {|o| "action_name == '#{o}'"}.join(" || ")
52
+ options[to] = Array(options[to]).unshift(from)
53
+ end
54
+ end
55
+
56
+ # Take callback names and an optional callback proc, normalize them,
57
+ # then call the block with each callback. This allows us to abstract
58
+ # the normalization across several methods that use it.
59
+ #
60
+ # ==== Parameters
61
+ # * <tt>callbacks</tt> - An array of callbacks, with an optional
62
+ # options hash as the last parameter.
63
+ # * <tt>block</tt> - A proc that should be added to the callbacks.
64
+ #
65
+ # ==== Block Parameters
66
+ # * <tt>name</tt> - The callback to be added
67
+ # * <tt>options</tt> - A hash of options to be used when adding the callback
68
+ def _insert_callbacks(callbacks, block = nil)
69
+ options = callbacks.extract_options!
70
+ _normalize_callback_options(options)
71
+ callbacks.push(block) if block
72
+ callbacks.each do |callback|
73
+ yield callback, options
74
+ end
75
+ end
76
+
77
+ ##
78
+ # :method: before_action
79
+ #
80
+ # :call-seq: before_action(names, block)
81
+ #
82
+ # Append a callback before actions. See _insert_callbacks for parameter details.
83
+
84
+ ##
85
+ # :method: prepend_before_action
86
+ #
87
+ # :call-seq: prepend_before_action(names, block)
88
+ #
89
+ # Prepend a callback before actions. See _insert_callbacks for parameter details.
90
+
91
+ ##
92
+ # :method: skip_before_action
93
+ #
94
+ # :call-seq: skip_before_action(names)
95
+ #
96
+ # Skip a callback before actions. See _insert_callbacks for parameter details.
97
+
98
+ ##
99
+ # :method: append_before_action
100
+ #
101
+ # :call-seq: append_before_action(names, block)
102
+ #
103
+ # Append a callback before actions. See _insert_callbacks for parameter details.
104
+
105
+ ##
106
+ # :method: after_action
107
+ #
108
+ # :call-seq: after_action(names, block)
109
+ #
110
+ # Append a callback after actions. See _insert_callbacks for parameter details.
111
+
112
+ ##
113
+ # :method: prepend_after_action
114
+ #
115
+ # :call-seq: prepend_after_action(names, block)
116
+ #
117
+ # Prepend a callback after actions. See _insert_callbacks for parameter details.
118
+
119
+ ##
120
+ # :method: skip_after_action
121
+ #
122
+ # :call-seq: skip_after_action(names)
123
+ #
124
+ # Skip a callback after actions. See _insert_callbacks for parameter details.
125
+
126
+ ##
127
+ # :method: append_after_action
128
+ #
129
+ # :call-seq: append_after_action(names, block)
130
+ #
131
+ # Append a callback after actions. See _insert_callbacks for parameter details.
132
+
133
+ ##
134
+ # :method: around_action
135
+ #
136
+ # :call-seq: around_action(names, block)
137
+ #
138
+ # Append a callback around actions. See _insert_callbacks for parameter details.
139
+
140
+ ##
141
+ # :method: prepend_around_action
142
+ #
143
+ # :call-seq: prepend_around_action(names, block)
144
+ #
145
+ # Prepend a callback around actions. See _insert_callbacks for parameter details.
146
+
147
+ ##
148
+ # :method: skip_around_action
149
+ #
150
+ # :call-seq: skip_around_action(names)
151
+ #
152
+ # Skip a callback around actions. See _insert_callbacks for parameter details.
153
+
154
+ ##
155
+ # :method: append_around_action
156
+ #
157
+ # :call-seq: append_around_action(names, block)
158
+ #
159
+ # Append a callback around actions. See _insert_callbacks for parameter details.
160
+
161
+ # set up before_action, prepend_before_action, skip_before_action, etc.
162
+ # for each of before, after, and around.
163
+ [:before, :after, :around].each do |callback|
164
+ define_method "#{callback}_action" do |*names, &blk|
165
+ _insert_callbacks(names, blk) do |name, options|
166
+ set_callback(:call_action, callback, name, options)
167
+ end
168
+ end
169
+
170
+ define_method "prepend_#{callback}_action" do |*names, &blk|
171
+ _insert_callbacks(names, blk) do |name, options|
172
+ set_callback(:call_action, callback, name, options.merge(:prepend => true))
173
+ end
174
+ end
175
+
176
+ # Skip a before, after or around callback. See _insert_callbacks
177
+ # for details on the allowed parameters.
178
+ define_method "skip_#{callback}_action" do |*names|
179
+ _insert_callbacks(names) do |name, options|
180
+ skip_callback(:call_action, callback, name, options)
181
+ end
182
+ end
183
+
184
+ # *_action is the same as append_*_action
185
+ alias_method :"append_#{callback}_action", :"#{callback}_action"
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,30 @@
1
+ module SimpleController
2
+ class Base
3
+ module Core
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ attr_reader :params, :action_name
8
+ end
9
+
10
+ def call(action_name, params={})
11
+ @params ||= ActiveSupport::HashWithIndifferentAccess.new(params)
12
+ @action_name ||= action_name.to_s
13
+
14
+ call_action
15
+ end
16
+
17
+ protected
18
+
19
+ def call_action
20
+ public_send action_name
21
+ end
22
+
23
+ module ClassMethods
24
+ def call(*args)
25
+ new.call *args
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
- require 'simple_controller/core'
2
- require 'simple_controller/callbacks'
1
+ require 'simple_controller/base/core'
2
+ require 'simple_controller/base/callbacks'
3
3
 
4
4
  module SimpleController
5
5
  class Base
@@ -0,0 +1,68 @@
1
+ require 'simple_controller/router/route'
2
+
3
+ module SimpleController
4
+ class Router
5
+ class Mapper
6
+ attr_reader :router, :namespaces, :controller_name
7
+
8
+ def initialize(router, namespaces=[], controller_name=nil)
9
+ @router, @namespaces, @controller_name = router, namespaces, controller_name
10
+ end
11
+
12
+ def namespace(namespace, &block)
13
+ @namespaces << namespace
14
+
15
+ mapper = self.class.new(router, namespaces, controller_name)
16
+ mapper.instance_eval(&block)
17
+ ensure
18
+ @namespaces.pop
19
+ end
20
+
21
+ def controller(controller_name, options={}, &block)
22
+ raise "can't have multiple controller scopes" if self.controller_name
23
+
24
+ mapper = self.class.new(router, namespaces, controller_name)
25
+ Array(options[:actions]).each { |action| mapper.match(action) }
26
+
27
+ mapper.instance_eval(&block) if block_given?
28
+ end
29
+
30
+ def match(arg)
31
+ route_path, partition = parse_match_arg(arg)
32
+
33
+ route_parts = [route_path]
34
+ route_parts.unshift(self.controller_name) if self.controller_name
35
+ route_parts.unshift(*namespaces)
36
+
37
+ controller_name_parts = [self.controller_name || partition.first]
38
+ controller_name_parts.unshift(*namespaces)
39
+
40
+ action_name = partition.last
41
+
42
+ router.add_route join_parts(route_parts), Route.new(join_parts(controller_name_parts), action_name)
43
+ end
44
+
45
+ protected
46
+ def join_parts(parts)
47
+ parts.map do |part|
48
+ s = part.to_s.dup
49
+ s.chomp!("/")
50
+ s.slice!(0) if part[0] == "/"
51
+ s
52
+ end.join("/")
53
+ end
54
+
55
+ def parse_match_arg(arg)
56
+ if arg.class == Hash
57
+ raise "takes only one option" unless arg.size == 1
58
+ route_path = arg.keys.first.to_s
59
+ partition = arg.values.first.to_s.rpartition("#")
60
+ else
61
+ route_path = arg.to_s
62
+ partition = route_path.rpartition("/")
63
+ end
64
+ [route_path, partition]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,20 @@
1
+ module SimpleController
2
+ class Router
3
+ class Route
4
+ attr_reader :controller_name, :action_name
5
+ attr_accessor :controller_name_block
6
+
7
+ def initialize(controller_name, action_name)
8
+ @controller_name, @action_name = controller_name, action_name
9
+ end
10
+
11
+ def controller(controller_name_block=nil)
12
+ controller_name_block ? controller_name_block.call(controller_name) : "#{controller_name}_controller".classify.constantize
13
+ end
14
+
15
+ def call(params, controller_name_block=nil)
16
+ controller(controller_name_block).call action_name, params
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,55 @@
1
+ require 'simple_controller/router/mapper'
2
+
3
+ module SimpleController
4
+ class Router
5
+ attr_reader :route_mapping, :route, :route_path, :controller_name_block
6
+
7
+ include ActiveSupport::Callbacks
8
+ define_callbacks :call
9
+
10
+ def initialize
11
+ @route_mapping = {}
12
+ end
13
+
14
+ def call(route_path, params={})
15
+ @route_path = route_path.to_s
16
+ @route = @route_mapping[@route_path]
17
+
18
+ raise "#{self.class} route for '#{@route_path}' not found" unless route
19
+
20
+ run_callbacks(:call) do
21
+ @route.call params, controller_name_block
22
+ end
23
+ ensure
24
+ @route_path = nil
25
+ @route = nil
26
+ end
27
+
28
+ def route_paths
29
+ route_mapping.keys
30
+ end
31
+
32
+ def draw(&block)
33
+ mapper = Mapper.new(self)
34
+ mapper.instance_eval(&block)
35
+ end
36
+
37
+ def add_route(route_path, route)
38
+ @route_mapping[route_path] = route
39
+ end
40
+
41
+ def parse_controller_name(&block)
42
+ @controller_name_block = block
43
+ end
44
+
45
+ class << self
46
+ def instance
47
+ @instance ||= new
48
+ end
49
+
50
+ def call(*args)
51
+ instance.call(*args)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,3 +1,3 @@
1
1
  module SimpleController
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -5,11 +5,13 @@ require "simple_controller/version"
5
5
 
6
6
  require 'active_support/callbacks'
7
7
  require 'active_support/hash_with_indifferent_access'
8
+ require 'active_support/inflector'
8
9
 
9
10
  if autoload && defined?(Rails)
10
11
  require 'simple_controller/engine'
11
12
  else
12
13
  require 'simple_controller/base'
14
+ require 'simple_controller/router'
13
15
  end
14
16
 
15
17
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Chung
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-07 00:00:00.000000000 Z
11
+ date: 2015-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -42,9 +42,12 @@ files:
42
42
  - bin/setup
43
43
  - lib/simple_controller.rb
44
44
  - lib/simple_controller/base.rb
45
- - lib/simple_controller/callbacks.rb
46
- - lib/simple_controller/core.rb
45
+ - lib/simple_controller/base/callbacks.rb
46
+ - lib/simple_controller/base/core.rb
47
47
  - lib/simple_controller/engine.rb
48
+ - lib/simple_controller/router.rb
49
+ - lib/simple_controller/router/mapper.rb
50
+ - lib/simple_controller/router/route.rb
48
51
  - lib/simple_controller/version.rb
49
52
  - simple_controller.gemspec
50
53
  homepage: https://github.com/FinalCAD/simple_controller
@@ -1,188 +0,0 @@
1
- # based on: https://github.com/rails/rails/blob/d2876141d08341ec67cf6a11a073d1acfb920de7/actionpack/lib/abstract_controller/callbacks.rb
2
- module SimpleController
3
- module Callbacks
4
- extend ActiveSupport::Concern
5
-
6
- # Uses ActiveSupport::Callbacks as the base functionality. For
7
- # more details on the whole callback system, read the documentation
8
- # for ActiveSupport::Callbacks.
9
- include ActiveSupport::Callbacks
10
-
11
- included do
12
- define_callbacks :call_action
13
- end
14
-
15
- # Override SimpleController::Base's call to run the
16
- # call callbacks around the normal behavior.
17
- def call_action(*args)
18
- run_callbacks(:call_action) do
19
- super
20
- end
21
- end
22
-
23
- module ClassMethods
24
- # If +:only+ or +:except+ are used, convert the options into the
25
- # +:if+ and +:unless+ options of ActiveSupport::Callbacks.
26
- #
27
- # The basic idea is that <tt>:only => :index</tt> gets converted to
28
- # <tt>:if => proc {|c| c.action_name == "index" }</tt>.
29
- #
30
- # Note that <tt>:only</tt> has priority over <tt>:if</tt> in case they
31
- # are used together.
32
- #
33
- # only: :index, if: -> { true } # the :if option will be ignored.
34
- #
35
- # Note that <tt>:if</tt> has priority over <tt>:except</tt> in case they
36
- # are used together.
37
- #
38
- # except: :index, if: -> { true } # the :except option will be ignored.
39
- #
40
- # ==== Options
41
- # * <tt>only</tt> - The callback should be run only for this action
42
- # * <tt>except</tt> - The callback should be run for all actions except this action
43
- def _normalize_callback_options(options)
44
- _normalize_callback_option(options, :only, :if)
45
- _normalize_callback_option(options, :except, :unless)
46
- end
47
-
48
- def _normalize_callback_option(options, from, to) # :nodoc:
49
- if from = options[from]
50
- from = Array(from).map {|o| "action_name == '#{o}'"}.join(" || ")
51
- options[to] = Array(options[to]).unshift(from)
52
- end
53
- end
54
-
55
- # Take callback names and an optional callback proc, normalize them,
56
- # then call the block with each callback. This allows us to abstract
57
- # the normalization across several methods that use it.
58
- #
59
- # ==== Parameters
60
- # * <tt>callbacks</tt> - An array of callbacks, with an optional
61
- # options hash as the last parameter.
62
- # * <tt>block</tt> - A proc that should be added to the callbacks.
63
- #
64
- # ==== Block Parameters
65
- # * <tt>name</tt> - The callback to be added
66
- # * <tt>options</tt> - A hash of options to be used when adding the callback
67
- def _insert_callbacks(callbacks, block = nil)
68
- options = callbacks.extract_options!
69
- _normalize_callback_options(options)
70
- callbacks.push(block) if block
71
- callbacks.each do |callback|
72
- yield callback, options
73
- end
74
- end
75
-
76
- ##
77
- # :method: before_action
78
- #
79
- # :call-seq: before_action(names, block)
80
- #
81
- # Append a callback before actions. See _insert_callbacks for parameter details.
82
-
83
- ##
84
- # :method: prepend_before_action
85
- #
86
- # :call-seq: prepend_before_action(names, block)
87
- #
88
- # Prepend a callback before actions. See _insert_callbacks for parameter details.
89
-
90
- ##
91
- # :method: skip_before_action
92
- #
93
- # :call-seq: skip_before_action(names)
94
- #
95
- # Skip a callback before actions. See _insert_callbacks for parameter details.
96
-
97
- ##
98
- # :method: append_before_action
99
- #
100
- # :call-seq: append_before_action(names, block)
101
- #
102
- # Append a callback before actions. See _insert_callbacks for parameter details.
103
-
104
- ##
105
- # :method: after_action
106
- #
107
- # :call-seq: after_action(names, block)
108
- #
109
- # Append a callback after actions. See _insert_callbacks for parameter details.
110
-
111
- ##
112
- # :method: prepend_after_action
113
- #
114
- # :call-seq: prepend_after_action(names, block)
115
- #
116
- # Prepend a callback after actions. See _insert_callbacks for parameter details.
117
-
118
- ##
119
- # :method: skip_after_action
120
- #
121
- # :call-seq: skip_after_action(names)
122
- #
123
- # Skip a callback after actions. See _insert_callbacks for parameter details.
124
-
125
- ##
126
- # :method: append_after_action
127
- #
128
- # :call-seq: append_after_action(names, block)
129
- #
130
- # Append a callback after actions. See _insert_callbacks for parameter details.
131
-
132
- ##
133
- # :method: around_action
134
- #
135
- # :call-seq: around_action(names, block)
136
- #
137
- # Append a callback around actions. See _insert_callbacks for parameter details.
138
-
139
- ##
140
- # :method: prepend_around_action
141
- #
142
- # :call-seq: prepend_around_action(names, block)
143
- #
144
- # Prepend a callback around actions. See _insert_callbacks for parameter details.
145
-
146
- ##
147
- # :method: skip_around_action
148
- #
149
- # :call-seq: skip_around_action(names)
150
- #
151
- # Skip a callback around actions. See _insert_callbacks for parameter details.
152
-
153
- ##
154
- # :method: append_around_action
155
- #
156
- # :call-seq: append_around_action(names, block)
157
- #
158
- # Append a callback around actions. See _insert_callbacks for parameter details.
159
-
160
- # set up before_action, prepend_before_action, skip_before_action, etc.
161
- # for each of before, after, and around.
162
- [:before, :after, :around].each do |callback|
163
- define_method "#{callback}_action" do |*names, &blk|
164
- _insert_callbacks(names, blk) do |name, options|
165
- set_callback(:call_action, callback, name, options)
166
- end
167
- end
168
-
169
- define_method "prepend_#{callback}_action" do |*names, &blk|
170
- _insert_callbacks(names, blk) do |name, options|
171
- set_callback(:call_action, callback, name, options.merge(:prepend => true))
172
- end
173
- end
174
-
175
- # Skip a before, after or around callback. See _insert_callbacks
176
- # for details on the allowed parameters.
177
- define_method "skip_#{callback}_action" do |*names|
178
- _insert_callbacks(names) do |name, options|
179
- skip_callback(:call_action, callback, name, options)
180
- end
181
- end
182
-
183
- # *_action is the same as append_*_action
184
- alias_method :"append_#{callback}_action", :"#{callback}_action"
185
- end
186
- end
187
- end
188
- end
@@ -1,28 +0,0 @@
1
- module SimpleController
2
- module Core
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- attr_reader :params, :action_name
7
- end
8
-
9
- def call(action_name, params={})
10
- @params ||= ActiveSupport::HashWithIndifferentAccess.new(params)
11
- @action_name ||= action_name.to_s
12
-
13
- call_action
14
- end
15
-
16
- protected
17
-
18
- def call_action
19
- public_send action_name
20
- end
21
-
22
- module ClassMethods
23
- def call(*args)
24
- new.call *args
25
- end
26
- end
27
- end
28
- end