mvcli 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mvcli/actions.rb +7 -4
- data/lib/mvcli/app.rb +8 -4
- data/lib/mvcli/erb.rb +40 -0
- data/lib/mvcli/loader.rb +15 -0
- data/lib/mvcli/renderer.rb +16 -0
- data/lib/mvcli/router.rb +26 -15
- data/lib/mvcli/version.rb +1 -1
- data/spec/mvcli/actions_spec.rb +2 -3
- data/spec/mvcli/erb_spec.rb +14 -0
- data/spec/mvcli/loader_spec.rb +13 -0
- data/spec/mvcli/router_spec.rb +15 -37
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d38bca7cf98c3cad670fe5df941fd17c8d8cd267
|
4
|
+
data.tar.gz: a1438f4ab557e0f083b9eca8875b67a2b9b12a27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b707863564e785f0fe67fe47712a2ba416214708a4ae6fce7d9500e5d5347b6c2bc0b2112186bade3fda1baf1b7f1426c2eb0199189615e59d2b90e3b3969dd4
|
7
|
+
data.tar.gz: 1add93e30613c13ba50b798543e76975df840a4f4b563cb83af8988118848994fdedfdd8e08c2772cc39e3f2e95f2a6864e074212bd02c5e7033fc9f30ded21d
|
data/lib/mvcli/actions.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
require_relative "loader"
|
2
|
+
require_relative "renderer"
|
3
|
+
|
1
4
|
module MVCLI
|
2
5
|
class Actions
|
3
|
-
def initialize(loader, renderer)
|
4
|
-
@loader = loader
|
5
|
-
@renderer = renderer
|
6
|
+
def initialize(root, loader = nil, renderer = nil)
|
7
|
+
@loader = loader || Loader.new(root)
|
8
|
+
@renderer = renderer || Renderer.new(root)
|
6
9
|
end
|
7
10
|
|
8
11
|
def [](key)
|
@@ -20,10 +23,10 @@ module MVCLI
|
|
20
23
|
|
21
24
|
def call(command)
|
22
25
|
controller = @loader.load :controller, @controller
|
23
|
-
fail LoadError, "no such controller: #{@controller}" unless controller
|
24
26
|
context = controller.send @method
|
25
27
|
path = [@controller, @method].join('/')
|
26
28
|
@renderer.render command.output, path, context
|
29
|
+
return 0
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
data/lib/mvcli/app.rb
CHANGED
@@ -1,23 +1,27 @@
|
|
1
1
|
require_relative "middleware"
|
2
2
|
require_relative "command"
|
3
|
+
require_relative "actions"
|
3
4
|
require_relative "router"
|
4
5
|
|
5
6
|
module MVCLI
|
6
7
|
class App
|
7
|
-
|
8
8
|
def initialize
|
9
|
-
@
|
10
|
-
@
|
9
|
+
@router = Router.new Actions.new root
|
10
|
+
@router.instance_eval route_file.read, route_file.to_s, 1
|
11
11
|
end
|
12
12
|
|
13
13
|
def call(command)
|
14
|
-
@
|
14
|
+
@router.call command
|
15
15
|
end
|
16
16
|
|
17
17
|
def root
|
18
18
|
self.class.root or fail "Invalid App: undefined application root directory"
|
19
19
|
end
|
20
20
|
|
21
|
+
def route_file
|
22
|
+
root.join 'app/routes.rb'
|
23
|
+
end
|
24
|
+
|
21
25
|
class << self
|
22
26
|
attr_accessor :root
|
23
27
|
end
|
data/lib/mvcli/erb.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "erb"
|
2
|
+
|
3
|
+
module MVCLI
|
4
|
+
class ERB
|
5
|
+
def initialize
|
6
|
+
@compiler = ::ERB::Compiler.new("<>")
|
7
|
+
@compiler.pre_cmd = [""]
|
8
|
+
@compiler.put_cmd = "@_erbout <<"
|
9
|
+
@compiler.insert_cmd = "@_erbout <<"
|
10
|
+
@compiler.post_cmd = ["nil"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile(string, filename = '(erb)')
|
14
|
+
code, enc = @compiler.compile string
|
15
|
+
Template.new code, enc, filename
|
16
|
+
end
|
17
|
+
|
18
|
+
class Template
|
19
|
+
def initialize(code, enc, filename)
|
20
|
+
@code, @enc, @filename = code, enc, filename
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(context, output)
|
24
|
+
binding = context.instance_eval do
|
25
|
+
@_erbout = output
|
26
|
+
Kernel.binding
|
27
|
+
end
|
28
|
+
eval @code, binding, @filename, 1
|
29
|
+
ensure
|
30
|
+
context.remove_instance_variable(:@_erbout)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_proc
|
34
|
+
proc do |context, output|
|
35
|
+
call context, output
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/mvcli/loader.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module MVCLI
|
2
|
+
class Loader
|
3
|
+
def initialize(path)
|
4
|
+
@path = path
|
5
|
+
end
|
6
|
+
|
7
|
+
def load(type, name)
|
8
|
+
pathname = "#{name}_#{type}"
|
9
|
+
filename = File.join(@path, "app/#{type}s", pathname)
|
10
|
+
require filename
|
11
|
+
classname = pathname.capitalize.gsub(/_(\w)/) {|m| m[1].upcase}
|
12
|
+
Object.const_get(classname).new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mvcli/erb'
|
2
|
+
|
3
|
+
module MVCLI
|
4
|
+
class Renderer
|
5
|
+
def initialize(root)
|
6
|
+
@root = root
|
7
|
+
end
|
8
|
+
|
9
|
+
def render(output, path, context)
|
10
|
+
filename = @root.join('app/views', path + '.txt.erb').to_s
|
11
|
+
compiler = MVCLI::ERB.new
|
12
|
+
template = compiler.compile File.read(filename), filename
|
13
|
+
template.call(context, output)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/mvcli/router.rb
CHANGED
@@ -7,28 +7,39 @@ module MVCLI
|
|
7
7
|
|
8
8
|
def initialize(actions = nil)
|
9
9
|
@actions = actions || Map.new
|
10
|
-
@
|
10
|
+
@routes = []
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
action = options
|
15
|
-
|
16
|
-
|
17
|
-
@root[verb] = action
|
18
|
-
end
|
13
|
+
def match(options)
|
14
|
+
pattern, action = options.first
|
15
|
+
options.delete pattern
|
16
|
+
@routes << Route.new(pattern, @actions, action, options)
|
19
17
|
end
|
20
18
|
|
21
19
|
def call(command)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
if route = @routes.find {|r| r.matches? command}
|
21
|
+
return route.call command
|
22
|
+
end
|
23
|
+
fail RoutingError, "no route matches '#{command.argv.join ' '}'"
|
24
|
+
end
|
25
|
+
|
26
|
+
class Route
|
27
|
+
def initialize(pattern, actions, action, options = {})
|
28
|
+
@pattern, @actions, @action, @options = pattern.to_s, actions, action, options
|
29
|
+
end
|
30
|
+
|
31
|
+
def matches?(command)
|
32
|
+
segments = @pattern.split /\s+/
|
33
|
+
segments.each_with_index do |s, i|
|
34
|
+
return false unless command.argv[i] && s.to_s == command.argv[i]
|
29
35
|
end
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
|
39
|
+
def call(command)
|
40
|
+
action = @actions[@action] or fail "no action found for #{@action}"
|
41
|
+
action.call command
|
30
42
|
end
|
31
|
-
fail RoutingError, "#{path.join(':')} does not respond to #{verb}"
|
32
43
|
end
|
33
44
|
end
|
34
45
|
end
|
data/lib/mvcli/version.rb
CHANGED
data/spec/mvcli/actions_spec.rb
CHANGED
@@ -4,11 +4,10 @@ require "mvcli/actions"
|
|
4
4
|
describe "MVCLI::Actions" do
|
5
5
|
Given(:loader) {mock(:Loader)}
|
6
6
|
Given(:renderer) {mock(:Renderer, :render => true)}
|
7
|
-
Given(:actions) {MVCLI::Actions.new loader, renderer}
|
7
|
+
Given(:actions) {MVCLI::Actions.new '/root', loader, renderer}
|
8
8
|
|
9
9
|
context "when the loader cannot find an appropriate controller" do
|
10
|
-
Given {loader.stub(:load)}
|
11
|
-
|
10
|
+
Given {loader.stub(:load) {fail LoadError}}
|
12
11
|
When(:action) {actions['foo']}
|
13
12
|
Then {action.should_not be_nil}
|
14
13
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "mvcli/erb"
|
3
|
+
|
4
|
+
describe "MVCLI::ERB" do
|
5
|
+
Given(:erb) {MVCLI::ERB.new}
|
6
|
+
context "when I compile a template" do
|
7
|
+
Given(:output) {""}
|
8
|
+
Given(:template) {erb.compile "name: <%= name %>"}
|
9
|
+
context "and call it with a context" do
|
10
|
+
When {template.call mock(:Context, :name => 'Charles'), output}
|
11
|
+
Then {output.should eql "name: Charles"}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "mvcli/loader"
|
3
|
+
|
4
|
+
describe "MVCLI::Loader" do
|
5
|
+
|
6
|
+
Given {class ::TotallyAwesomeController; end}
|
7
|
+
Given(:loader) {MVCLI::Loader.new '/path/to/app'}
|
8
|
+
Given {loader.stub(:require) {true}}
|
9
|
+
context "loading a controller in the global namespace" do
|
10
|
+
When(:controller){loader.load :controller, 'totally_awesome'}
|
11
|
+
Then {controller.should be_instance_of TotallyAwesomeController}
|
12
|
+
end
|
13
|
+
end
|
data/spec/mvcli/router_spec.rb
CHANGED
@@ -5,53 +5,31 @@ describe "MVCLI::Router" do
|
|
5
5
|
Given(:Router) {MVCLI::Router}
|
6
6
|
Given(:actions) {mock(:Actions)}
|
7
7
|
Given(:router) {self.Router.new actions}
|
8
|
+
Given {actions.stub(:[]) {|action| @action = action; ->(command) {@command = command}}}
|
9
|
+
|
8
10
|
|
9
11
|
context "without any routes" do
|
10
12
|
When(:result) {invoke}
|
11
13
|
Then {result.should have_failed self.Router::RoutingError}
|
12
14
|
end
|
13
15
|
|
14
|
-
context "
|
15
|
-
|
16
|
-
Then {result.should have_failed}
|
17
|
-
end
|
18
|
-
|
19
|
-
context "with its root mapped to a single verb" do
|
20
|
-
Given do
|
21
|
-
actions.stub(:[]).with('logins#create') do
|
22
|
-
proc do |command|
|
23
|
-
@login = command
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
Given {router.root :to => 'logins#create', :via => :login}
|
16
|
+
context "with a route matched to an action" do
|
17
|
+
Given {router.match 'login' => 'logins#create'}
|
28
18
|
When {invoke 'login'}
|
29
|
-
Then {@
|
19
|
+
Then {@action.should eql 'logins#create'}
|
20
|
+
And {@command.should_not be_nil}
|
21
|
+
Then {@command.argv.should eql ['login']}
|
22
|
+
end
|
30
23
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
context "and a second verb is mapped to the the root" do
|
36
|
-
Given do
|
37
|
-
actions.stub(:[]).with('logins#destroy') {proc {|c| @logout = c}}
|
38
|
-
end
|
39
|
-
Given {router.root :to => 'logins#destroy', :via => :logout}
|
40
|
-
context "when I access via the original verb" do
|
41
|
-
Given {invoke 'logout' }
|
42
|
-
Then {@logout.should_not be_nil}
|
43
|
-
And {@logout.argv.should eql ['logout']}
|
44
|
-
end
|
45
|
-
end
|
24
|
+
context "with a route matched to a block" do
|
25
|
+
Given {router.match bam: ->(command) {@command = command}}
|
26
|
+
When {invoke 'bam'}
|
27
|
+
Then {@command.argv.should eql ['bam']}
|
46
28
|
end
|
47
29
|
|
48
|
-
context "with
|
49
|
-
Given
|
50
|
-
|
51
|
-
end
|
52
|
-
Given {router.root :to => 'something#show'}
|
53
|
-
When {invoke 'help'}
|
54
|
-
Then {@something.argv.should eql ['help']}
|
30
|
+
context "with a route with dynamic segments" do
|
31
|
+
Given {router.match 'show loadbalancer :name' => 'loadbalancers#show'}
|
32
|
+
When(:result) {invoke 'show loadbalancer 6'}
|
55
33
|
end
|
56
34
|
|
57
35
|
def invoke(*args)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mvcli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Lowell
|
@@ -29,7 +29,7 @@ cert_chain:
|
|
29
29
|
UgImJlChAzCoDP9zi9tdm6jAr7ttF25R9PPYr11ILb7dYe3qUzlNlM6zJx/nb31b
|
30
30
|
IhdyRVup4qLcqYSTPsm6u7VA
|
31
31
|
-----END CERTIFICATE-----
|
32
|
-
date: 2013-05-
|
32
|
+
date: 2013-05-22 00:00:00.000000000 Z
|
33
33
|
dependencies:
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: map
|
@@ -63,11 +63,16 @@ files:
|
|
63
63
|
- lib/mvcli/actions.rb
|
64
64
|
- lib/mvcli/app.rb
|
65
65
|
- lib/mvcli/command.rb
|
66
|
+
- lib/mvcli/erb.rb
|
67
|
+
- lib/mvcli/loader.rb
|
66
68
|
- lib/mvcli/middleware.rb
|
69
|
+
- lib/mvcli/renderer.rb
|
67
70
|
- lib/mvcli/router.rb
|
68
71
|
- lib/mvcli/version.rb
|
69
72
|
- mvcli.gemspec
|
70
73
|
- spec/mvcli/actions_spec.rb
|
74
|
+
- spec/mvcli/erb_spec.rb
|
75
|
+
- spec/mvcli/loader_spec.rb
|
71
76
|
- spec/mvcli/middleware_spec.rb
|
72
77
|
- spec/mvcli/router_spec.rb
|
73
78
|
- spec/spec_helper.rb
|
@@ -97,6 +102,8 @@ specification_version: 4
|
|
97
102
|
summary: Local Apps. Remote Apps. They're all at your fingertips
|
98
103
|
test_files:
|
99
104
|
- spec/mvcli/actions_spec.rb
|
105
|
+
- spec/mvcli/erb_spec.rb
|
106
|
+
- spec/mvcli/loader_spec.rb
|
100
107
|
- spec/mvcli/middleware_spec.rb
|
101
108
|
- spec/mvcli/router_spec.rb
|
102
109
|
- spec/spec_helper.rb
|