mvcli 0.0.16 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +4 -0
  3. data/Gemfile +2 -2
  4. data/README.md +6 -2
  5. data/app.rb +7 -0
  6. data/app/routes.rb +0 -0
  7. data/bin/mvcli +5 -0
  8. data/lib/mvcli.rb +1 -0
  9. data/lib/mvcli/action.rb +31 -0
  10. data/lib/mvcli/app.rb +23 -28
  11. data/lib/mvcli/controller.rb +20 -2
  12. data/lib/mvcli/core.rb +101 -0
  13. data/lib/mvcli/cortex.rb +38 -0
  14. data/lib/mvcli/form.rb +13 -0
  15. data/lib/mvcli/loader.rb +45 -1
  16. data/lib/mvcli/middleware.rb +13 -15
  17. data/lib/mvcli/path.rb +41 -0
  18. data/lib/mvcli/plugins.rb +19 -0
  19. data/lib/mvcli/plugins/controllers/plugins_controller.rb +23 -0
  20. data/lib/mvcli/plugins/forms/plugins/install_form.rb +6 -0
  21. data/lib/mvcli/plugins/models/plugins/installation_model.rb +33 -0
  22. data/lib/mvcli/plugins/providers/bundle_provider.rb +116 -0
  23. data/lib/mvcli/plugins/routes.rb +3 -0
  24. data/lib/mvcli/plugins/templates/plugins/index.txt.erb +3 -0
  25. data/lib/mvcli/plugins/templates/plugins/install.txt.erb +1 -0
  26. data/lib/mvcli/plugins/templates/plugins/uninstall.txt.erb +1 -0
  27. data/lib/mvcli/provisioning.rb +48 -38
  28. data/lib/mvcli/router.rb +34 -20
  29. data/lib/mvcli/std/extensions/erb_extension.rb +24 -0
  30. data/lib/mvcli/std/providers/argv_provider.rb +9 -0
  31. data/lib/mvcli/std/providers/config_provider.rb +29 -0
  32. data/lib/mvcli/std/providers/middleware_provider.rb +12 -0
  33. data/lib/mvcli/std/providers/router_provider.rb +17 -0
  34. data/lib/mvcli/std/routes.rb +2 -0
  35. data/lib/mvcli/version.rb +1 -1
  36. data/spec/features/managing_plugins_spec.rb +29 -0
  37. data/spec/fixtures/apps/trivium/app.rb +10 -0
  38. data/spec/fixtures/apps/trivium/app/routes.rb +0 -0
  39. data/spec/fixtures/apps/trivium/bin/trivium +6 -0
  40. data/spec/fixtures/apps/trivium/lib/trivium/version.rb +3 -0
  41. data/spec/fixtures/apps/trivium/trivium.gemspec +8 -0
  42. data/spec/fixtures/bin/trivium +3 -0
  43. data/spec/fixtures/plugins/timing-plugin/app/routes.rb +1 -0
  44. data/spec/fixtures/plugins/timing-plugin/lib/trivium-timing.rb +5 -0
  45. data/spec/fixtures/plugins/timing-plugin/trivium-timing.gemspec +9 -0
  46. data/spec/mvcli/action_spec.rb +31 -0
  47. data/spec/mvcli/controller_spec.rb +35 -0
  48. data/spec/mvcli/core_spec.rb +77 -0
  49. data/spec/mvcli/cortex_spec.rb +50 -0
  50. data/spec/mvcli/erb_spec.rb +1 -1
  51. data/spec/mvcli/form_spec.rb +1 -1
  52. data/spec/mvcli/loader_spec.rb +58 -13
  53. data/spec/mvcli/middleware/exception_logger_spec.rb +3 -3
  54. data/spec/mvcli/middleware/exit_status_spec.rb +10 -10
  55. data/spec/mvcli/middleware_spec.rb +28 -45
  56. data/spec/mvcli/path_spec.rb +13 -0
  57. data/spec/mvcli/path_spec/does/exist +1 -0
  58. data/spec/mvcli/plugins/providers/bundle_provider_spec.rb +23 -0
  59. data/spec/mvcli/provisioning_spec.rb +39 -37
  60. data/spec/mvcli/router_spec.rb +26 -32
  61. data/spec/mvcli/std/extensions/erb_extension_spec.rb +34 -0
  62. data/spec/mvcli/std/providers/middleware_provider_spec.rb +10 -0
  63. data/spec/mvcli/validatable_spec.rb +12 -12
  64. data/spec/spec_helper.rb +13 -1
  65. data/spec/support/aruba_helper.rb +76 -0
  66. metadata +69 -33
  67. data/lib/mvcli/actions.rb +0 -37
  68. data/lib/mvcli/renderer.rb +0 -16
  69. data/spec/mvcli/actions_spec.rb +0 -34
  70. data/spec/mvcli/dummy/app/providers/test_provider.rb +0 -5
@@ -4,10 +4,10 @@ require "mvcli/middleware/exception_logger"
4
4
  describe "MVCLI::Middleware::ExceptionLogger" do
5
5
  use_natural_assertions
6
6
 
7
- Given(:command) {mock(:Command, :log => "")}
8
- Given(:logger) {MVCLI::Middleware::ExceptionLogger.new}
7
+ Given(:command) { double(:Command, :log => "") }
8
+ Given(:logger) { MVCLI::Middleware::ExceptionLogger.new }
9
9
  context "with a cleanly running application" do
10
- When(:result) {logger.call(command) {0}}
10
+ When(:result) { logger.call(command) {0} }
11
11
  Then {result == 0}
12
12
  end
13
13
  context "with an app that raises an exception" do
@@ -3,24 +3,24 @@ require "mvcli/middleware/exit_status"
3
3
 
4
4
  describe MVCLI::Middleware::ExitStatus do
5
5
  use_natural_assertions
6
- Given(:command) {mock(:Command)}
7
- Given(:middleware) {MVCLI::Middleware::ExitStatus.new}
6
+ Given(:command) { double(:Command) }
7
+ Given(:middleware) { MVCLI::Middleware::ExitStatus.new }
8
8
  context "when called with code that succeeds" do
9
- When(:status) {middleware.call(command) {0}}
10
- Then {status == 0}
9
+ When(:status) { middleware.call(command) {0} }
10
+ Then { status == 0 }
11
11
  end
12
12
  context "when called with an app that fails with an exit status of 99" do
13
- When(:status) {middleware.call(command) {99}}
14
- Then{ status == 99}
13
+ When(:status) { middleware.call(command) {99} }
14
+ Then { status == 99 }
15
15
  end
16
16
 
17
17
  context "when the upstream app yields a non-integer" do
18
- When(:status) {middleware.call(command) {"whoopeee!"}}
19
- Then {status == 0}
18
+ When(:status) { middleware.call(command) {"whoopeee!"} }
19
+ Then { status == 0 }
20
20
  end
21
21
 
22
22
  context "when the upstream app raises an exception" do
23
- When(:status) {middleware.call(command) {fail "boom!"}}
24
- Then {status == 70}
23
+ When(:status) { middleware.call(command) {fail "boom!"} }
24
+ Then { status == 70 }
25
25
  end
26
26
  end
@@ -2,73 +2,56 @@ require "spec_helper"
2
2
  require "mvcli/middleware"
3
3
 
4
4
  describe "MVCLI::Middleware" do
5
- before do
6
- @middleware = MVCLI::Middleware.new
7
- @command = mock(:Command)
8
- end
5
+ use_natural_assertions
6
+ Given(:middleware) { MVCLI::Middleware.new }
7
+ Given(:command) { double :Command }
8
+
9
+ When { @result = middleware.call command }
9
10
 
10
- it "runs perfectly fine without any apps" do
11
- @middleware.call(@command).should eql 0
11
+ context "without any apps" do
12
+ Then { @result == 0 }
12
13
  end
13
14
 
14
- describe "with a single app" do
15
- before do
16
- @app = proc do |command|
15
+ context "with a single app" do
16
+ Given do
17
+ middleware << proc do |command|
17
18
  @called = command
18
19
  end
19
- @middleware << @app
20
- @middleware.call @command
21
- end
22
- it "calls it" do
23
- @called.should eql @command
24
20
  end
21
+ Then { @called == command }
25
22
  end
26
23
 
27
- describe "with a couple apps" do
28
- before do
24
+ context "with a couple of apps" do
25
+ Given do
29
26
  @sequence = []
30
27
  @commands = []
31
- @middleware << proc do |command, &block|
28
+ middleware << proc do |command, &block|
32
29
  @commands << command
33
30
  @sequence << "first.before"
34
31
  block.call
35
32
  @sequence << "first.after"
36
33
  end
37
- @middleware << proc do |command, &block|
34
+ middleware << proc do |command, &block|
38
35
  @commands << command
39
36
  @sequence << "second"
40
37
  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
38
  end
39
+ Then { @commands == [command, command] }
40
+ Then { @sequence == ["first.before", "second", "first.after"] }
49
41
 
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
42
+ context "when the first does not yield to the second" do
43
+ Given { middleware[0] = Proc.new {} }
44
+ Then { @sequence == [] }
59
45
  end
60
46
  end
61
47
 
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
48
+ context "with a single app that yields even though there is no next app" do
49
+ Given { middleware << proc {|c, &block| block.call } }
50
+ Then { @result == 0 }
51
+ end
52
+
53
+ context "when invoked with a 'follow-on' app" do
54
+ When(:result) { middleware.call(command) {|c| c} }
55
+ Then { result == command }
73
56
  end
74
57
  end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+ require "mvcli/path"
3
+
4
+ describe "MVCLI::Path" do
5
+ use_natural_assertions
6
+ Given(:path) { MVCLI::Path.new(Pathname(__FILE__).dirname.join(File.basename __FILE__, '.rb')) }
7
+
8
+ Then { path.exists? 'does/exist' }
9
+ Then { not path.exists? 'does/not/exist' }
10
+ Then { path.read('does/exist') == "Hello World"}
11
+ Then { path.to_s('flim flam') =~ %r{mvcli/spec/mvcli/path_spec/flim flam} }
12
+ Then { path.nearest('spec_helper.rb') == Pathname(__FILE__).parent.parent.join('spec_helper.rb') }
13
+ end
@@ -0,0 +1 @@
1
+ Hello World
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+ require "mvcli/plugins/providers/bundle_provider"
3
+ require "bundler/ui"
4
+
5
+
6
+
7
+ describe "Bundle Provider" do
8
+ # Given(:bundle) { MVCLI::BundleProvider.new }
9
+ # Given(:dir) { Pathname(__FILE__).dirname.join('tmp/plugins') }
10
+ # Given do
11
+ # bundle.stub(:dir) { dir }
12
+ # FileUtils.rm_rf dir.to_s
13
+ # FileUtils.mkdir_p dir.to_s
14
+ # end
15
+ # describe "replacing a gem in the bundle" do
16
+ # When { bundle.replace "trivium-timing", require: 'trivium-timing', path: File.expand_path('../../../../fixtures/plugins/timing-plugin', __FILE__) }
17
+ # When { bundle.replace "ref" }
18
+ # describe "activating the bundle" do
19
+ # When { bundle.activate! }
20
+ # Then { "it's in the classpath now" }
21
+ # end
22
+ # end
23
+ end
@@ -3,54 +3,56 @@ require "mvcli/provisioning"
3
3
 
4
4
  describe "Provisioning" do
5
5
  use_natural_assertions
6
+
6
7
  describe "Scope" do
7
- Given(:provisioner) {{}}
8
- Given(:mod) {Module.new {include MVCLI::Provisioning}}
9
- Given(:cls) {m = mod; Class.new {include m}}
10
- Given(:obj) {cls.new}
11
- Given(:command) {mock(:Command)}
12
- Given(:scope) {MVCLI::Provisioning::Scope.new command, provisioner}
8
+ Given(:scope) { MVCLI::Provisioning::Scope.new options }
9
+ Given(:command) { double :Command }
10
+ Given(:cortex) { double :Cortex }
11
+ Given(:mod) { Module.new {include MVCLI::Provisioning} }
12
+ Given(:cls) { m = mod; Class.new {include m} }
13
+ Given(:obj) { cls.new }
14
+
13
15
  context "when the command is required" do
14
- Given {mod.requires :command}
15
- When(:result) {scope.evaluate {obj.command}}
16
- Then {result == command}
16
+ Given { mod.requires :command }
17
+ Given(:options) { {command: command} }
18
+ When(:result) { scope.evaluate { obj.command } }
19
+ Then { result == command }
20
+ end
21
+ context "when the cortex is required" do
22
+ Given { mod.requires :cortex }
23
+ Given(:options) { {cortex: cortex} }
24
+ Then { scope.evaluate { obj.cortex } == cortex }
17
25
  end
18
26
  context "with a requirement is specified on the module" do
19
- Given {mod.requires :foo}
20
- context "when accessing it but it is not present" do
21
- When(:result) {scope.evaluate {obj.foo}}
22
- Then {result.should have_failed MVCLI::Provisioning::UnsatisfiedRequirement, /foo/}
27
+ Given(:options) { {cortex: cortex} }
28
+ Given { mod.requires :foo }
29
+ context "when reading it but it is not present" do
30
+ Given { cortex.stub(:read) { fail "no such provider" } }
31
+ When(:result) { scope.evaluate { obj.foo } }
32
+ Then { result.should have_failed StandardError, /no such/ }
33
+ And { cortex.should have_received(:read).with(:provider, :foo)}
34
+ context "but it is manually specified in an enclosing block" do
35
+ When(:result) { scope.evaluate(foo: 'bar') { obj.foo} }
36
+ Then { result == 'bar' }
37
+ context "and then not" do
38
+ When(:result) { scope.evaluate { obj.foo } }
39
+ Then { result.should have_failed }
40
+ end
41
+ end
23
42
  end
24
43
  context "and there is a scope which satisfies the requirement" do
25
- Given(:foo) {Object.new}
26
- Given {provisioner[:foo] = foo}
44
+ Given(:foo) { Object.new }
45
+ Given { cortex.stub(:read) { double(:Provider, value: foo)}}
27
46
 
28
- context "when a dependency is accessed in the context of the scope" do
29
- When(:result) {scope.evaluate {obj.foo}}
30
- Then {result == foo}
47
+ context "when a dependency is read in the context of the scope" do
48
+ When(:result) { scope.evaluate { obj.foo } }
49
+ Then { result == foo }
31
50
  end
32
51
  end
33
52
  context "accessing requirements with no scope" do
34
- When(:result) {obj.foo}
35
- Then {result.should have_failed MVCLI::Provisioning::MissingScope}
53
+ When(:result) { obj.foo }
54
+ Then { result.should have_failed MVCLI::Provisioning::MissingScope }
36
55
  end
37
56
  end
38
57
  end
39
-
40
- describe "Provisioner" do
41
- Given do
42
- ActiveSupport::Dependencies.clear
43
- ActiveSupport::Dependencies.autoload_paths.clear
44
- ActiveSupport::Dependencies.autoload_paths << File.expand_path('../dummy/app/providers', __FILE__)
45
- end
46
- Given(:provisioner) {MVCLI::Provisioning::Provisioner.new}
47
- context "when no provider exists for a value" do
48
- When(:result) {provisioner[:does_not_exist]}
49
- Then {result.should have_failed}
50
- end
51
- context "when a provider exists" do
52
- When(:result) {provisioner[:test]}
53
- Then {result == "here is a free value just for you!!"}
54
- end
55
- end
56
58
  end
@@ -4,57 +4,51 @@ require "mvcli/router"
4
4
  describe "MVCLI::Router" do
5
5
  use_natural_assertions
6
6
 
7
- Given(:Router) {MVCLI::Router}
8
- Given(:actions) {mock(:Actions)}
9
- Given(:router) {self.Router.new actions}
10
- Given do
11
- actions.stub(:[]) do |action|
12
- @action = action
13
- ->(command, bindings) {@command = command; @bindings = bindings}
14
- end
15
- end
7
+ Given(:Router) { MVCLI::Router}
8
+ Given(:routes) { self.Router::DSL.new }
9
+ Given(:router) { routes.router }
10
+ Given(:actions) { double(:Actions) }
11
+ Given { actions.stub(:new) { |match, mapping| Map match: match, mapping: mapping } }
12
+ Given { router.stub(:actions) { actions } }
16
13
 
17
14
  def invoke(route = '')
18
- router.call mock(:Command, :argv => route.split(/\s+/))
15
+ router.call double(:Command, :argv => route.split(/\s+/))
19
16
  end
20
17
 
21
18
  context "without any routes" do
22
- When(:result) {invoke}
23
- Then {result.should have_failed self.Router::RoutingError}
19
+ When(:result) { invoke }
20
+ Then { result.should have_failed self.Router::RoutingError }
24
21
  end
25
22
 
26
23
  context "with a route matched to an action" do
27
- Given {router.match 'login' => 'logins#create'}
28
- When {invoke 'login'}
29
- Then { @action == 'logins#create' }
30
- And { not @command.nil? }
31
- Then { @command.argv == ['login'] }
24
+ Given { routes.match 'login' => 'logins#create' }
25
+ When(:action) { invoke 'login' }
26
+ Then { action.mapping == 'logins#create' }
32
27
  end
33
28
 
34
29
  context "when there are command line options, it does not interfere" do
35
- Given { router.match 'login' => 'logins#create' }
36
- When { invoke 'login --then --go-away -f 6 -p' }
37
- Then { not @command.nil? }
30
+ Given { routes.match 'login' => 'logins#create' }
31
+ When(:action) { invoke 'login --then --go-away -f 6 -p' }
32
+ Then { action.mapping == 'logins#create' }
38
33
  end
39
34
 
40
35
  context "with a route matched to a block" do
41
- Given { router.match bam: ->(command) {@command = command} }
42
- When { invoke 'bam' }
43
- Then { @command.argv == ['bam'] }
36
+ Given { routes.match bam: ->(command) { command } }
37
+ When(:action) { invoke 'bam' }
38
+ Then { action.mapping.call('foo') == 'foo' }
44
39
  end
45
40
 
46
41
  context "with a route with captures" do
47
- Given { router.match 'show loadbalancer :id' => 'loadbalancers#show' }
48
- When { invoke 'show loadbalancer 6' }
49
- Then {@action == 'loadbalancers#show'}
50
- And { @command.argv == ['show', 'loadbalancer', '6'] }
51
- And { @bindings[:id] == '6' }
42
+ Given { routes.match 'show loadbalancer :id' => 'loadbalancers#show' }
43
+ When(:action) { invoke 'show loadbalancer 6' }
44
+ Then { action.mapping == 'loadbalancers#show'}
45
+ Then { action.match.bindings[:id] == '6' }
52
46
  end
53
47
 
54
48
  context "with macros" do
55
- Given { router.macro /(-h|--help) (.*)/ => "help \\2" }
56
- Given { router.match "help me" => "help#me"}
57
- When { invoke "--help me" }
58
- Then { @action == 'help#me' }
49
+ Given { routes.macro /(-h|--help) (.*)/ => "help \\2" }
50
+ Given { routes.match "help me" => "help#me"}
51
+ When(:action) { invoke "--help me" }
52
+ Then { action.mapping == 'help#me' }
59
53
  end
60
54
  end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+ require "mvcli/std/extensions/erb_extension"
3
+
4
+ describe "The ERB Extension" do
5
+ Given(:extension) { MVCLI::ERBExtension.new }
6
+ Given(:name) { 'foo/bar' }
7
+
8
+ describe "to_path" do
9
+ When(:path) { extension.to_path name, extension_type }
10
+ context "when the extension_type is a string" do
11
+ Given(:extension_type) { "template" }
12
+ Then { path == "templates/foo/bar.txt.erb" }
13
+ end
14
+ context "when the extension_type is a symbol" do
15
+ Given(:extension_type) { :template }
16
+ Then { path == "templates/foo/bar.txt.erb" }
17
+ end
18
+ context "when the extension_type is not 'template'" do
19
+ Given(:extension_type) { :not_a_template }
20
+ Then { path.should have_failed ArgumentError }
21
+ end
22
+ end
23
+ describe "define" do
24
+ Given(:extension_type) { :template }
25
+ Given(:namespace) { Object }
26
+ When(:template) { extension.define(name, bytes, extension_type, namespace) }
27
+ context "with a valid ERB template" do
28
+ Given(:bytes) { "Hello <%= this.name %>" }
29
+ Given(:output) { StringIO.new }
30
+ When { template.call Map(name: 'Bob'), output }
31
+ Then { output.string == 'Hello Bob' }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ require "spec_helper"
2
+ require "mvcli/std/providers/middleware_provider"
3
+
4
+ describe "building middleware" do
5
+ use_natural_assertions
6
+
7
+ When(:middleware) { MVCLI::MiddlewareProvider.new.value }
8
+ Then { middleware.should_not have_failed }
9
+ And { middleware.length == 2}
10
+ end
@@ -3,27 +3,27 @@ require "mvcli/validatable"
3
3
 
4
4
  describe "a validator" do
5
5
  use_natural_assertions
6
- Given(:object) {Object.new}
7
- Given(:validator) {MVCLI::Validatable::Validator.new}
6
+ Given(:object) { Object.new }
7
+ Given(:validator) { MVCLI::Validatable::Validator.new }
8
8
  Given(:validation) { validator.validate object }
9
9
  Given(:violations) { validation.violations }
10
10
 
11
11
  context "when it validates a field that does not exist on the object" do
12
- Given {validator.validates(:does_not_exist, "invalid") {}}
13
- When(:validation) {validator.validate object}
14
- Then {not validation.errors[:does_not_exist].empty?}
15
- Then {not validation.valid?}
12
+ Given { validator.validates(:does_not_exist, "invalid") {} }
13
+ When(:validation) { validator.validate object }
14
+ Then { not validation.errors[:does_not_exist].empty? }
15
+ Then { not validation.valid? }
16
16
  end
17
17
  describe "validating a child" do
18
- Given {validator.validates_child(:some_child)}
18
+ Given { validator.validates_child(:some_child) }
19
19
  context "when it is nil" do
20
- When(:validation) {validator.validate(mock(:Object, :some_child => nil))}
21
- Then {validation.valid?}
20
+ When(:validation) { validator.validate(double(:Object, :some_child => nil)) }
21
+ Then { validation.valid? }
22
22
  end
23
23
  context "when it does not exist" do
24
- When(:validation) {validator.validate(Object.new)}
25
- Then {not validation.errors[:some_child].nil?}
26
- And {not validation.valid?}
24
+ When(:validation) { validator.validate(Object.new) }
25
+ Then { not validation.errors[:some_child].nil? }
26
+ And { not validation.valid? }
27
27
  end
28
28
  end
29
29