simple_controller 0.1.1 → 1.0.0
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 +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +64 -6
- data/lib/simple_controller/base.rb +2 -0
- data/lib/simple_controller/base/context.rb +27 -0
- data/lib/simple_controller/base/core.rb +3 -1
- data/lib/simple_controller/router.rb +4 -50
- data/lib/simple_controller/router/context.rb +38 -0
- data/lib/simple_controller/router/core.rb +61 -0
- data/lib/simple_controller/router/mapper.rb +19 -19
- data/lib/simple_controller/router/route.rb +7 -9
- data/lib/simple_controller/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 524340d2ca7c377417e63196f002bf3d6c26e2ed
|
4
|
+
data.tar.gz: 9d7cefb26e4bd4821643eff5979143d5d113820e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ed3f6ed15a1a6567923ffd324fc15e4b550cba0a23be0455a8a26ad066f65e4396ff42f0eda1183d88068b0664b743ab987ff755eadf0db8db2644eaab60a23
|
7
|
+
data.tar.gz: 05e9b2d919c96ca1355fc364c7bcdd3b91dfd85920df263432f7d693070efc01b110e08e7c6cb7dc7945dc16cacdae01664f0690570ffd9d5ebfa2eb34078001
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -42,11 +42,10 @@ It works like a Rails Controller, but has only has the following features:
|
|
42
42
|
- `action_name`
|
43
43
|
|
44
44
|
## Router
|
45
|
-
|
45
|
+
An **optional** router is provided to decouple controller classes from identifiers.
|
46
46
|
|
47
47
|
```ruby
|
48
|
-
class Router < SimpleController::Router
|
49
|
-
end
|
48
|
+
class Router < SimpleController::Router; end
|
50
49
|
|
51
50
|
# Router.instance is a singleton for ease of use
|
52
51
|
Router.instance.draw do
|
@@ -71,9 +70,68 @@ Router.call("threes/multiply", number: 6) # calls ThreesController.call(:multipl
|
|
71
70
|
Router.instance.call("threes/multiply", number: 6) # same as above
|
72
71
|
```
|
73
72
|
|
74
|
-
To
|
73
|
+
To customize the controller class:
|
75
74
|
```ruby
|
76
|
-
Router.instance.
|
77
|
-
|
75
|
+
Router.instance.parse_controller_path do |controller_path|
|
76
|
+
# similar to default implementation
|
77
|
+
"#{controller_name}_suffix_controller".classify.constantize
|
78
|
+
end
|
78
79
|
Router.call("threes/multiply", number: 6) # calls ThreesSuffixController.call(:multiply, number: 6)
|
80
|
+
```
|
81
|
+
|
82
|
+
Routers add the following Rails features to the Controllers:
|
83
|
+
- `params[:action]` and `params[:controller]`
|
84
|
+
- `controller_path` and `controller_name`
|
85
|
+
|
86
|
+
## Post-Process
|
87
|
+
Inspired by [`rails/sprockets` Processors](https://github.com/rails/sprockets#using-processors), Routes can have processor suffixes to ensure that controller endpoints
|
88
|
+
are [composable](https://en.wikipedia.org/wiki/Function_composition_(computer_science)). For example, given:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
class FoldersController < FileSystemController
|
92
|
+
def two_readmes
|
93
|
+
dir = create_new_directory
|
94
|
+
dir.add_files Router.call('files/readme'), Router.call('files/readme')
|
95
|
+
dir.path
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class FilesController < FileSystemController
|
100
|
+
def readme
|
101
|
+
write_new_file_and_return_path
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
And the [Router](#router) is set up, `FoldersController#two_readmes` generates a directory of `FilesController#readme`s. Processors add the ability to do these calls:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
# calls the `s3_key` processor
|
110
|
+
Router.call('files/readme.s3_key')
|
111
|
+
# equivalent to:
|
112
|
+
FilesController.call(:readme, {}, { processors: [:s3_key] })
|
113
|
+
|
114
|
+
# calls the `zip` processor then the `s3_key` processor
|
115
|
+
Router.call('folders/two_readmes.s3_key.zip')
|
116
|
+
# equivalent to (NOTE the reverse order to the processor suffixes):
|
117
|
+
FoldersController.call(:two_readmes, {}, { processors: [:zip, :s3_key] })
|
118
|
+
```
|
119
|
+
|
120
|
+
The processors (`zip` and `s3_key`) can be defined and implemented in a common Parent controller, in this case:
|
121
|
+
```ruby
|
122
|
+
class FileSystemController < SimpleController::Base
|
123
|
+
# output => "path_to_file_or_directory"
|
124
|
+
# processors => some combination of [:zip, :s3_key]
|
125
|
+
def post_process(output, processors)
|
126
|
+
processors.each do |processor|
|
127
|
+
case processor
|
128
|
+
when :zip
|
129
|
+
output = zip_directory_and_return_path_of_zip(output)
|
130
|
+
when :s3_key
|
131
|
+
output = upload_file_path_to_amazon_s3_and_return_the_s3_key(output)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
output
|
135
|
+
end
|
136
|
+
end
|
79
137
|
```
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'simple_controller/base/core'
|
2
|
+
require 'simple_controller/base/context'
|
2
3
|
require 'simple_controller/base/callbacks'
|
3
4
|
|
4
5
|
module SimpleController
|
5
6
|
class Base
|
6
7
|
include Core
|
7
8
|
include Callbacks # included last to wrap method
|
9
|
+
include Context
|
8
10
|
end
|
9
11
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SimpleController
|
2
|
+
class Base
|
3
|
+
module Context
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_reader :context
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(action_name, params={}, context={})
|
11
|
+
@context ||= OpenStruct.new context
|
12
|
+
|
13
|
+
super(action_name, params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def call_action(*args)
|
17
|
+
post_process super, context.processors || []
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def post_process(output, processors)
|
23
|
+
output
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -4,12 +4,14 @@ module SimpleController
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
attr_reader :params, :action_name
|
7
|
+
attr_reader :params, :action_name, :controller_path, :controller_name
|
8
8
|
end
|
9
9
|
|
10
10
|
def call(action_name, params={})
|
11
11
|
@params ||= ActiveSupport::HashWithIndifferentAccess.new(params)
|
12
12
|
@action_name ||= action_name.to_s
|
13
|
+
@controller_path ||= params[:controller]
|
14
|
+
@controller_name ||= controller_path.split("/").last if controller_path
|
13
15
|
|
14
16
|
call_action
|
15
17
|
end
|
@@ -1,55 +1,9 @@
|
|
1
|
-
require 'simple_controller/router/
|
1
|
+
require 'simple_controller/router/core'
|
2
|
+
require 'simple_controller/router/context'
|
2
3
|
|
3
4
|
module SimpleController
|
4
5
|
class Router
|
5
|
-
|
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
|
6
|
+
include Core
|
7
|
+
include Context
|
54
8
|
end
|
55
9
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module SimpleController
|
2
|
+
class Router
|
3
|
+
module Context
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_reader :context
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(route_path, params={})
|
11
|
+
route_path = parse_route_path(route_path.to_s)
|
12
|
+
|
13
|
+
super(route_path, params)
|
14
|
+
ensure
|
15
|
+
@context = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def _call(route)
|
21
|
+
route.call params, context, controller_path_block
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_route_path(route_path)
|
25
|
+
processors = []
|
26
|
+
|
27
|
+
until (extension = File.extname(route_path)).empty?
|
28
|
+
route_path = route_path.chomp(extension)
|
29
|
+
processors << extension[1..-1].to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
@context = { processors: processors }
|
33
|
+
|
34
|
+
route_path
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'simple_controller/router/route'
|
2
|
+
require 'simple_controller/router/mapper'
|
3
|
+
|
4
|
+
module SimpleController
|
5
|
+
class Router
|
6
|
+
module Core
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
attr_reader :route_mapping, :route_path, :params, :controller_path_block
|
11
|
+
end
|
12
|
+
def initialize
|
13
|
+
@route_mapping = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(route_path, params={})
|
17
|
+
@route_path = route_path.to_s
|
18
|
+
@params = params
|
19
|
+
|
20
|
+
route = @route_mapping[@route_path]
|
21
|
+
raise "#{self.class} route for '#{@route_path}' not found" unless route
|
22
|
+
_call(route)
|
23
|
+
ensure
|
24
|
+
@route_path = @params = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def route_paths
|
28
|
+
route_mapping.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def draw(&block)
|
32
|
+
mapper = Mapper.new(self)
|
33
|
+
mapper.instance_eval(&block)
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_route(route_path, controller_path, action)
|
38
|
+
@route_mapping[route_path] = Route.new(controller_path, action)
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse_controller_path(&block)
|
42
|
+
@controller_path_block = block
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
def _call(route)
|
47
|
+
route.call params, controller_path_block
|
48
|
+
end
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
def instance
|
52
|
+
@instance ||= new
|
53
|
+
end
|
54
|
+
|
55
|
+
def call(*args)
|
56
|
+
instance.call(*args)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,45 +1,41 @@
|
|
1
|
-
require 'simple_controller/router/route'
|
2
|
-
|
3
1
|
module SimpleController
|
4
2
|
class Router
|
5
3
|
class Mapper
|
6
|
-
attr_reader :router, :namespaces, :
|
4
|
+
attr_reader :router, :namespaces, :controller_path
|
7
5
|
|
8
|
-
def initialize(router, namespaces=[],
|
9
|
-
@router, @namespaces, @
|
6
|
+
def initialize(router, namespaces=[], controller_path=nil)
|
7
|
+
@router, @namespaces, @controller_path = router, namespaces, controller_path
|
10
8
|
end
|
11
9
|
|
12
10
|
def namespace(namespace, &block)
|
13
11
|
@namespaces << namespace
|
14
12
|
|
15
|
-
mapper = self.class.new(router, namespaces,
|
13
|
+
mapper = self.class.new(router, namespaces, controller_path)
|
16
14
|
mapper.instance_eval(&block)
|
17
15
|
ensure
|
18
16
|
@namespaces.pop
|
19
17
|
end
|
20
18
|
|
21
|
-
def controller(
|
22
|
-
raise "can't have multiple controller scopes" if self.
|
19
|
+
def controller(controller_path, options={}, &block)
|
20
|
+
raise "can't have multiple controller scopes" if self.controller_path
|
23
21
|
|
24
|
-
mapper = self.class.new(router, namespaces,
|
22
|
+
mapper = self.class.new(router, namespaces, controller_path)
|
25
23
|
Array(options[:actions]).each { |action| mapper.match(action) }
|
26
24
|
|
27
25
|
mapper.instance_eval(&block) if block_given?
|
28
26
|
end
|
29
27
|
|
30
28
|
def match(arg)
|
31
|
-
route_path,
|
29
|
+
route_path, controller_name, action_name = parse_match_arg(arg)
|
32
30
|
|
33
31
|
route_parts = [route_path]
|
34
|
-
route_parts.unshift(self.
|
32
|
+
route_parts.unshift(self.controller_path) if self.controller_path
|
35
33
|
route_parts.unshift(*namespaces)
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
action_name = partition.last
|
35
|
+
controller_path_parts = [self.controller_path || controller_name]
|
36
|
+
controller_path_parts.unshift(*namespaces)
|
41
37
|
|
42
|
-
router.add_route join_parts(route_parts),
|
38
|
+
router.add_route join_parts(route_parts), join_parts(controller_path_parts), action_name
|
43
39
|
end
|
44
40
|
|
45
41
|
protected
|
@@ -54,14 +50,18 @@ module SimpleController
|
|
54
50
|
|
55
51
|
def parse_match_arg(arg)
|
56
52
|
if arg.class == Hash
|
53
|
+
# match "threes/dividing" => "threes#divide"
|
54
|
+
# match subtracting: "subtract"
|
57
55
|
raise "takes only one option" unless arg.size == 1
|
58
56
|
route_path = arg.keys.first.to_s
|
59
|
-
|
57
|
+
controller_name, _, action_name = arg.values.first.to_s.rpartition("#")
|
60
58
|
else
|
59
|
+
# match :threes
|
60
|
+
# match "threes/multiply"
|
61
61
|
route_path = arg.to_s
|
62
|
-
|
62
|
+
controller_name, _, action_name = route_path.rpartition("/")
|
63
63
|
end
|
64
|
-
[route_path,
|
64
|
+
[route_path, controller_name, action_name]
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
@@ -1,19 +1,17 @@
|
|
1
1
|
module SimpleController
|
2
2
|
class Router
|
3
3
|
class Route
|
4
|
-
attr_reader :
|
5
|
-
attr_accessor :controller_name_block
|
4
|
+
attr_reader :controller_path, :action_name
|
6
5
|
|
7
|
-
def initialize(
|
8
|
-
@
|
6
|
+
def initialize(controller_path, action_name)
|
7
|
+
@controller_path, @action_name = controller_path, action_name
|
9
8
|
end
|
10
9
|
|
11
|
-
def
|
12
|
-
|
13
|
-
end
|
10
|
+
def call(params, context, controller_path_block)
|
11
|
+
controller_class = controller_path_block ? controller_path_block.call(controller_path) : "#{controller_path}_controller".classify.constantize
|
14
12
|
|
15
|
-
|
16
|
-
|
13
|
+
params = { 'controller' => controller_path, 'action' => action_name }.reverse_merge(params)
|
14
|
+
controller_class.call action_name, params, context
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
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.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Chung
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- ".gitignore"
|
35
35
|
- ".rspec"
|
36
36
|
- ".travis.yml"
|
37
|
+
- CHANGELOG.md
|
37
38
|
- Gemfile
|
38
39
|
- LICENSE.txt
|
39
40
|
- README.md
|
@@ -43,9 +44,12 @@ files:
|
|
43
44
|
- lib/simple_controller.rb
|
44
45
|
- lib/simple_controller/base.rb
|
45
46
|
- lib/simple_controller/base/callbacks.rb
|
47
|
+
- lib/simple_controller/base/context.rb
|
46
48
|
- lib/simple_controller/base/core.rb
|
47
49
|
- lib/simple_controller/engine.rb
|
48
50
|
- lib/simple_controller/router.rb
|
51
|
+
- lib/simple_controller/router/context.rb
|
52
|
+
- lib/simple_controller/router/core.rb
|
49
53
|
- lib/simple_controller/router/mapper.rb
|
50
54
|
- lib/simple_controller/router/route.rb
|
51
55
|
- lib/simple_controller/version.rb
|
@@ -70,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
74
|
version: '0'
|
71
75
|
requirements: []
|
72
76
|
rubyforge_project:
|
73
|
-
rubygems_version: 2.
|
77
|
+
rubygems_version: 2.5.1
|
74
78
|
signing_key:
|
75
79
|
specification_version: 4
|
76
80
|
summary: Rails Controllers, but general purpose.
|