mvcli 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2af39b708e5b71d002d6734923412e067411c115
4
+ data.tar.gz: dcdf57432aeb3712a27878088ae4a527728b9ac2
5
+ SHA512:
6
+ metadata.gz: dceaaf28dae8821938e47b2c528330e6cacf7abe51bfddadf0ef94c0b4d201659e55bcf52188280d88fe3f92d01728adb1e2014bc048e78aae49d795f61e3e83
7
+ data.tar.gz: 4b6586b4eb3b18213257b23122114d66800419d1a1940b79c4c39512ffa33e87800a04feb7610315815f7d6e1187c591e1dc3f54ada6d70c80ac0aa3fecd1a86
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mvcli.gemspec
4
+ gemspec
5
+
6
+ gem "rake"
7
+ gem "rspec"
8
+ gem "rspec-given"
9
+ gem "rspec-spies"
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Charles Lowell
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ ## Mvcli
2
+
3
+ It's terribly frustrating when repos don't have a good README. But a
4
+ bad readme is worse than no README at all.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,10 @@
1
+ class LoadbalancersController < ApplicationController
2
+ include MVCLI::RemoteRestController
3
+
4
+ respond_to :txt, :json, :xml
5
+ performs :create, :show, :update, :destroy
6
+
7
+ param :name, :type => :string
8
+
9
+
10
+ end
data/example/routes.rb ADDED
@@ -0,0 +1,31 @@
1
+ collection :loadbalancers do
2
+ # match "create loadbalancer"
3
+ # match "show loadbalancers"
4
+ # match "loadbalancers"
5
+ # match "show loadbalancer :id" #=> 'loadbalancers#show'
6
+ # match "update loadbalancer :id #=> loadbalancers#update"
7
+ # match "destroy loadbalancer :id"
8
+ collection :nodes do
9
+ # match "create node on loadbalancer :loadbalancer_id"
10
+ # match "create loadbalancer :loadbalancer_id node"
11
+ # match "show nodes on loadbalancer :loadbalancer_id"
12
+ # match "loadbalancer nodes"
13
+ # match "show loadbalancer :loadbalancer_id nodes"
14
+ # match "show loadbalancer :loadbalancer_id node :id"
15
+ # match "show node :id on loadbalancer :loadbalancer_id"
16
+ # match "update loadbalancer:node"
17
+ # match "destroy loadbalancer:node:$id"
18
+ # match "destroy loadbalancer node $id"
19
+ # match "destroy loadbalancer:node $id"
20
+ # match "help "
21
+ end
22
+
23
+ collection :virtual_ips, :only => :index
24
+ # match "show virtual_ips on loadbalancer :loadbalancer_id"
25
+ # match "show loadbalancer :loadbalancer_id virtual_ips"
26
+ # match "loadbalancers"
27
+ end
28
+
29
+ collection :servers do
30
+
31
+ end
@@ -0,0 +1,30 @@
1
+ module MVCLI
2
+ class Actions
3
+ def initialize(loader, renderer)
4
+ @loader = loader
5
+ @renderer = renderer
6
+ end
7
+
8
+ def [](key)
9
+ controller, method = key.split('#')
10
+ Action.new @loader, @renderer, controller, method
11
+ end
12
+
13
+ class Action
14
+ def initialize(loader, renderer, controller, method)
15
+ @loader = loader
16
+ @renderer = renderer
17
+ @controller = controller
18
+ @method = method
19
+ end
20
+
21
+ def call(command)
22
+ controller = @loader.load :controller, @controller
23
+ fail LoadError, "no such controller: #{@controller}" unless controller
24
+ context = controller.send @method
25
+ path = [@controller, @method].join('/')
26
+ @renderer.render command.output, path, context
27
+ end
28
+ end
29
+ end
30
+ end
data/lib/mvcli/app.rb ADDED
@@ -0,0 +1,33 @@
1
+ require_relative "middleware"
2
+ require_relative "command"
3
+ require_relative "router"
4
+
5
+ module MVCLI
6
+ class App
7
+
8
+ def initialize
9
+ @middleware = Middleware.new
10
+ @middleware << Router.new
11
+ end
12
+
13
+ def call(command)
14
+ @middleware.call command
15
+ end
16
+
17
+ def root
18
+ self.class.root or fail "Invalid App: undefined application root directory"
19
+ end
20
+
21
+ class << self
22
+ attr_accessor :root
23
+ end
24
+
25
+ def main(argv = ARGV.dup, input = $stdin, output = $stdout, log = $stderr, env = ENV.dup)
26
+ call Command.new(argv, input, output, log, env)
27
+ end
28
+
29
+ def self.main(*args)
30
+ new.main *args
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ module MVCLI
2
+ class Command
3
+ attr_reader :argv, :input, :output, :log, :env
4
+
5
+ def initialize(argv, input, output, log, env)
6
+ @argv, @input, @output, @log, @env = argv, input, output, log, env
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,38 @@
1
+ module MVCLI
2
+ class Middleware
3
+ def initialize
4
+ @apps = []
5
+ end
6
+
7
+ def call(command)
8
+ invoke command, 0
9
+ end
10
+
11
+ def [](idx)
12
+ @apps[idx]
13
+ end
14
+
15
+ def []=(idx, app)
16
+ @apps[idx] = app
17
+ end
18
+
19
+ def <<(app)
20
+ @apps << app
21
+ end
22
+
23
+ private
24
+
25
+ def invoke(command, index)
26
+ if app = @apps[index]
27
+ app.call(command) do |c|
28
+ if @apps[index + 1]
29
+ c ||= command
30
+ invoke c, index + 1
31
+ end
32
+ end
33
+ else
34
+ return 0
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ require "map"
2
+
3
+ module MVCLI
4
+ class Router
5
+ RoutingError = Class.new StandardError
6
+ InvalidRoute = Class.new RoutingError
7
+
8
+ def initialize(actions = nil)
9
+ @actions = actions || Map.new
10
+ @root = Map.new
11
+ end
12
+
13
+ def root(options = {})
14
+ action = options[:to] or fail InvalidRoute, "root routes must specify an action with ':to =>' E.g. root :to => 'foo#bar'"
15
+ verbs = [options[:via] || :help].flatten
16
+ verbs.each do |verb|
17
+ @root[verb] = action
18
+ end
19
+ end
20
+
21
+ def call(command)
22
+ verb = command.argv.first || 'help'
23
+ path = command.argv.slice(1..-1) || []
24
+ if path.empty?
25
+ if action_name = @root[verb]
26
+ if action = @actions[action_name]
27
+ return action.call command
28
+ end
29
+ end
30
+ end
31
+ fail RoutingError, "#{path.join(':')} does not respond to #{verb}"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module MVCLI
2
+ VERSION = "0.0.1"
3
+ end
data/lib/mvcli.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "mvcli/version"
2
+
3
+ module MVCLI
4
+ # Your code goes here...
5
+ end
data/mvcli.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mvcli/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mvcli"
8
+ spec.version = MVCLI::VERSION
9
+ spec.authors = ["Charles Lowell"]
10
+ spec.email = ["cowboyd@thefrontside.net"]
11
+ spec.description = %q{MVC Framework for Building Command Line Apps}
12
+ spec.summary = %q{Local Apps. Remote Apps. They're all at your fingertips}
13
+ spec.homepage = "https://github.com/cowboyd/mvcli"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "map"
22
+ end
@@ -0,0 +1,30 @@
1
+ require "spec_helper"
2
+ require "mvcli/actions"
3
+
4
+ describe "MVCLI::Actions" do
5
+ Given(:loader) {mock(:Loader)}
6
+ Given(:renderer) {mock(:Renderer, :render => true)}
7
+ Given(:actions) {MVCLI::Actions.new loader, renderer}
8
+
9
+ context "when the loader cannot find an appropriate controller" do
10
+ Given {loader.stub(:load)}
11
+
12
+ When(:action) {actions['foo']}
13
+ Then {action.should_not be_nil}
14
+
15
+ context ".calling it" do
16
+ When(:result) {action.call(mock(:Command))}
17
+ Then {result.should have_failed LoadError}
18
+ end
19
+ end
20
+
21
+ context "when the class exists" do
22
+ Given(:output) {mock(:Output)}
23
+ Given(:controller) {mock(:Controller)}
24
+ Given {loader.stub(:load).with(:controller, 'foo') {controller}}
25
+ Given {controller.stub(:bar) {"the context"}}
26
+ When {actions['foo#bar'].call(mock(:Command, :output => output))}
27
+ Then {controller.should have_received(:bar)}
28
+ And {renderer.should have_received(:render).with(output, 'foo/bar', 'the context')}
29
+ end
30
+ end
@@ -0,0 +1,74 @@
1
+ require "spec_helper"
2
+ require "mvcli/middleware"
3
+
4
+ describe "MVCLI::Middleware" do
5
+ before do
6
+ @middleware = MVCLI::Middleware.new
7
+ @command = mock(:Command)
8
+ end
9
+
10
+ it "runs perfectly fine without any apps" do
11
+ @middleware.call(@command).should eql 0
12
+ end
13
+
14
+ describe "with a single app" do
15
+ before do
16
+ @app = proc do |command|
17
+ @called = command
18
+ end
19
+ @middleware << @app
20
+ @middleware.call @command
21
+ end
22
+ it "calls it" do
23
+ @called.should eql @command
24
+ end
25
+ end
26
+
27
+ describe "with a couple apps" do
28
+ before do
29
+ @sequence = []
30
+ @commands = []
31
+ @middleware << proc do |command, &block|
32
+ @commands << command
33
+ @sequence << "first.before"
34
+ block.call
35
+ @sequence << "first.after"
36
+ end
37
+ @middleware << proc do |command, &block|
38
+ @commands << command
39
+ @sequence << "second"
40
+ end
41
+ @middleware.call @command
42
+ end
43
+ it "passes the command to all the apps" do
44
+ @commands.should eql [@command, @command]
45
+ end
46
+ it "calls the first app *around* the second app" do
47
+ @sequence.should eql ["first.before", "second", "first.after"]
48
+ end
49
+
50
+ describe "if the first app does not yield" do
51
+ before do
52
+ @sequence.clear
53
+ @middleware[0] = Proc.new {}
54
+ @middleware.call @command
55
+ end
56
+ it "never calls the second app" do
57
+ @sequence.should eql []
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "with an app that yields even though there is no next app" do
63
+ before do
64
+ app = Object.new
65
+ def app.call(command)
66
+ yield
67
+ end
68
+ @middleware << @app
69
+ end
70
+ it "runs successfully" do
71
+ @middleware.call(@command).should eql 0
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,60 @@
1
+ require "spec_helper"
2
+ require "mvcli/router"
3
+
4
+ describe "MVCLI::Router" do
5
+ Given(:Router) {MVCLI::Router}
6
+ Given(:actions) {mock(:Actions)}
7
+ Given(:router) {self.Router.new actions}
8
+
9
+ context "without any routes" do
10
+ When(:result) {invoke}
11
+ Then {result.should have_failed self.Router::RoutingError}
12
+ end
13
+
14
+ context "when an invalid root is mapped" do
15
+ When(:result) {router.root :wat => :tf?}
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}
28
+ When {invoke 'login'}
29
+ Then {@login.argv.should eql ['login']}
30
+
31
+ context "when a command comes in for an unmapped verb" do
32
+ When(:result) {invoke 'fwiff'}
33
+ Then {result.should have_failed self.Router::RoutingError}
34
+ end
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
46
+ end
47
+
48
+ context "with its root mapped without a specific verb" do
49
+ Given do
50
+ actions.stub(:[]).with('something#show') {proc {|c|@something = c}}
51
+ end
52
+ Given {router.root :to => 'something#show'}
53
+ When {invoke 'help'}
54
+ Then {@something.argv.should eql ['help']}
55
+ end
56
+
57
+ def invoke(*args)
58
+ router.call mock(:Command, :argv => args)
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ require "mvcli"
2
+ require "rspec-given"
3
+ require "rspec-spies"
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mvcli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Charles Lowell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDPjCCAiagAwIBAgIBADANBgkqhkiG9w0BAQUFADBFMRAwDgYDVQQDDAdjb3di
14
+ b3lkMRwwGgYKCZImiZPyLGQBGRYMdGhlZnJvbnRzaWRlMRMwEQYKCZImiZPyLGQB
15
+ GRYDbmV0MB4XDTEzMDEzMDIxMDYwNFoXDTE0MDEzMDIxMDYwNFowRTEQMA4GA1UE
16
+ AwwHY293Ym95ZDEcMBoGCgmSJomT8ixkARkWDHRoZWZyb250c2lkZTETMBEGCgmS
17
+ JomT8ixkARkWA25ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO45
18
+ CUxpETDGYXjCCy2dMg/aIrdrTqBqQW5ZrzhHxF9EkcdmWFr0z/qMz0JSpZ3pF11Z
19
+ KYaj5PaQQpjZfLPwbuiGGkuSWi+UAac//V18xo6S4lzRBjO+gpzG9f2AOzt9b+SR
20
+ Uc8UhO7QBZ5edUDxMxw9QstD+U0YBAlzsPJbHuUOqdtxXmNQCds3ZnqTgZaIpdUy
21
+ CSejtrukSmlthxFzwgMezYQhcYxmkl+Q475JUodnI6Pjc6nja/Or8Y6cEWiLgeUa
22
+ a+efcPGLDEbwJC7TGRrvk8yassMByBEJ3XueTMzeqWFd+665ptciojYo6BvIAR0N
23
+ iLwks0x567FZyS8SqTcCAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUxVgR
24
+ 5TUqf7Hd24ICb3g4FNbM7oYwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IB
25
+ AQDdJj+NzZhiYXA56z0wzRUA/Fcf6CYqKB+RFRlPssDEcHTor5SnwdWgQof/gNLi
26
+ Qel1Om4zO0Shcp89jxaUqtvEdYVhmyfc0vycHmemKttNBT734yMrEJtF8Hhy+Dnz
27
+ 9CzixXLvgGaRH+mf3M0+l+zIDJJr2L+39L8cyTSSRnp/srfI8aSmJKhGshudBKoC
28
+ Ty6Gi071pwoJXvdMaE/6iPy7bUzlndYdHyYuWSKaO9N47HqQ62oEnBraglw6ghoi
29
+ UgImJlChAzCoDP9zi9tdm6jAr7ttF25R9PPYr11ILb7dYe3qUzlNlM6zJx/nb31b
30
+ IhdyRVup4qLcqYSTPsm6u7VA
31
+ -----END CERTIFICATE-----
32
+ date: 2013-05-20 00:00:00.000000000 Z
33
+ dependencies:
34
+ - !ruby/object:Gem::Dependency
35
+ name: map
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ description: MVC Framework for Building Command Line Apps
49
+ email:
50
+ - cowboyd@thefrontside.net
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - .gitignore
56
+ - Gemfile
57
+ - LICENSE.txt
58
+ - README.md
59
+ - Rakefile
60
+ - example/controllers/loadbalancers_controller.rb
61
+ - example/routes.rb
62
+ - lib/mvcli.rb
63
+ - lib/mvcli/actions.rb
64
+ - lib/mvcli/app.rb
65
+ - lib/mvcli/command.rb
66
+ - lib/mvcli/middleware.rb
67
+ - lib/mvcli/router.rb
68
+ - lib/mvcli/version.rb
69
+ - mvcli.gemspec
70
+ - spec/mvcli/actions_spec.rb
71
+ - spec/mvcli/middleware_spec.rb
72
+ - spec/mvcli/router_spec.rb
73
+ - spec/spec_helper.rb
74
+ homepage: https://github.com/cowboyd/mvcli
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.0.0
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Local Apps. Remote Apps. They're all at your fingertips
98
+ test_files:
99
+ - spec/mvcli/actions_spec.rb
100
+ - spec/mvcli/middleware_spec.rb
101
+ - spec/mvcli/router_spec.rb
102
+ - spec/spec_helper.rb