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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 022feec11ef15f421596afc8ab71a0f69dd271ed
4
- data.tar.gz: e048c155d5ad1b659a0a5dd45eada31a64f46916
3
+ metadata.gz: 524340d2ca7c377417e63196f002bf3d6c26e2ed
4
+ data.tar.gz: 9d7cefb26e4bd4821643eff5979143d5d113820e
5
5
  SHA512:
6
- metadata.gz: 52542cc33f334c554d80e15dbb635993c2562e77b3ea3d7536ddd8ec2be80c28105e5cabd0e9d5774717965cdd78c1d7a4e20168e07d1518d847454336cdbf55
7
- data.tar.gz: eb967704ba637c82038b0ce0611fe8eecdf07d50320dead670c0123f9c7b4f53f4da0a3b10b71617e4d834350b5cf84207f11facffbf19b31a4a859ffac9acc9
6
+ metadata.gz: 6ed3f6ed15a1a6567923ffd324fc15e4b550cba0a23be0455a8a26ad066f65e4396ff42f0eda1183d88068b0664b743ab987ff755eadf0db8db2644eaab60a23
7
+ data.tar.gz: 05e9b2d919c96ca1355fc364c7bcdd3b91dfd85920df263432f7d693070efc01b110e08e7c6cb7dc7945dc16cacdae01664f0690570ffd9d5ebfa2eb34078001
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # SimpleController Breaking Changes
2
+ ## 1.0.0
3
+ - rename `controller_name` to `controller_path` to match Rails convention
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
- A router is provided to decouple controller classes from identifiers.
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 custom namespace the controller:
73
+ To customize the controller class:
75
74
  ```ruby
76
- Router.instance.parse_controller_name {|controller_name| "#{controller_name}_suffix_controller".classify.constantize }
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/mapper'
1
+ require 'simple_controller/router/core'
2
+ require 'simple_controller/router/context'
2
3
 
3
4
  module SimpleController
4
5
  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
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, :controller_name
4
+ attr_reader :router, :namespaces, :controller_path
7
5
 
8
- def initialize(router, namespaces=[], controller_name=nil)
9
- @router, @namespaces, @controller_name = router, namespaces, controller_name
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, controller_name)
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(controller_name, options={}, &block)
22
- raise "can't have multiple controller scopes" if self.controller_name
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, controller_name)
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, partition = parse_match_arg(arg)
29
+ route_path, controller_name, action_name = parse_match_arg(arg)
32
30
 
33
31
  route_parts = [route_path]
34
- route_parts.unshift(self.controller_name) if self.controller_name
32
+ route_parts.unshift(self.controller_path) if self.controller_path
35
33
  route_parts.unshift(*namespaces)
36
34
 
37
- controller_name_parts = [self.controller_name || partition.first]
38
- controller_name_parts.unshift(*namespaces)
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), Route.new(join_parts(controller_name_parts), action_name)
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
- partition = arg.values.first.to_s.rpartition("#")
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
- partition = route_path.rpartition("/")
62
+ controller_name, _, action_name = route_path.rpartition("/")
63
63
  end
64
- [route_path, partition]
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 :controller_name, :action_name
5
- attr_accessor :controller_name_block
4
+ attr_reader :controller_path, :action_name
6
5
 
7
- def initialize(controller_name, action_name)
8
- @controller_name, @action_name = controller_name, action_name
6
+ def initialize(controller_path, action_name)
7
+ @controller_path, @action_name = controller_path, action_name
9
8
  end
10
9
 
11
- def controller(controller_name_block=nil)
12
- controller_name_block ? controller_name_block.call(controller_name) : "#{controller_name}_controller".classify.constantize
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
- def call(params, controller_name_block=nil)
16
- controller(controller_name_block).call action_name, params
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
@@ -1,3 +1,3 @@
1
1
  module SimpleController
2
- VERSION = "0.1.1"
2
+ VERSION = "1.0.0"
3
3
  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.1.1
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: 2015-12-15 00:00:00.000000000 Z
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.4.5.1
77
+ rubygems_version: 2.5.1
74
78
  signing_key:
75
79
  specification_version: 4
76
80
  summary: Rails Controllers, but general purpose.