mvcli 0.0.6 → 0.0.7

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: d1f731e4ba8f382b06704c3051bda33ded0ef7ce
4
- data.tar.gz: 2ad3d53e76c0eb40e9980275c3dcb1fbbe33ea82
3
+ metadata.gz: 39bb6d037a235e80b610d16a1cff026dd0945134
4
+ data.tar.gz: 42a1e909308dea92677bf8e76abb6dcee1d8358f
5
5
  SHA512:
6
- metadata.gz: 8b329020fa0bd200d8d85b177a905b434838a68748ad67fc344e438693e7e293bdc61b998495a73271e13aa0ab21d9150a520b8cea0bc7c057d9c53c865221c8
7
- data.tar.gz: fdd24ba8968d733efae785848919313ba4e8cd77ca15063ae9dde273fc4b61bb95fdd712140ca826b417a7cdcb9a0dafd0b8ef12fbd7d023326ea283d0b8e7b8
6
+ metadata.gz: 2812db9dc93f3a3ec99d6cfa5b2af883e6ed04af8aea8538404b28b5969234c14c3b71615996011dbd348e7e4343de0ec923e48078487e3d3142a9da6b6b5a8f
7
+ data.tar.gz: e2913626bac2de10934365c49a80924365885aac67c7bf23f76764a1ed8ca53fd08792b38dd04dae92aa5c2619385b89b44309552d46216115203bf148b962ab
data/lib/mvcli/actions.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require "map"
2
+ require "mvcli/controller"
3
+ require "mvcli/form"
2
4
  require_relative "loader"
3
5
  require_relative "renderer"
4
6
 
data/lib/mvcli/app.rb CHANGED
@@ -12,8 +12,9 @@ module MVCLI
12
12
  def initialize
13
13
  @router = Router.new Actions.new root
14
14
  @router.instance_eval route_file.read, route_file.to_s, 1
15
- ActiveSupport::Dependencies.autoload_paths << root.join('app/providers')
16
- ActiveSupport::Dependencies.autoload_paths << root.join('app/controllers')
15
+ [:providers, :controllers, :forms, :models].each do |path|
16
+ ActiveSupport::Dependencies.autoload_paths << root.join('app', path.to_s)
17
+ end
17
18
  @middleware = Middleware.new
18
19
  @middleware << Provisioning::Middleware.new
19
20
  @middleware << @router
data/lib/mvcli/argv.rb ADDED
@@ -0,0 +1,48 @@
1
+ require "map"
2
+
3
+ class MVCLI::Argv
4
+ attr_reader :arguments, :options
5
+
6
+ def initialize(argv, switches = [])
7
+ @switches = switches.map(&:to_s)
8
+ @arguments, @options = scan argv
9
+ end
10
+
11
+ def scan(argv, arguments = [], options = Map.new)
12
+ current, *rest = argv
13
+ case current
14
+ when nil
15
+ [arguments, options]
16
+ when /^--(\w[[:graph:]]+)=([[:graph:]]+)$/
17
+ scan rest, arguments, merge(options, $1, $2)
18
+ when /^--no-(\w[[:graph:]]+)$/
19
+ scan rest, arguments, merge(options, $1, false)
20
+ when /^--(\w[[:graph:]]+)$/, /^-(\w)$/
21
+ key = underscore $1
22
+ if switch? key
23
+ scan rest, arguments, merge(options, key, true)
24
+ elsif rest.first =~ /^-/
25
+ scan rest, arguments, merge(options, key)
26
+ else
27
+ value, *rest = rest
28
+ scan rest, arguments, merge(options, key, value)
29
+ end
30
+ else
31
+ scan rest, arguments + [current], options
32
+ end
33
+ end
34
+
35
+ def switch?(key)
36
+ @switches.member? underscore key
37
+ end
38
+
39
+ def merge(options, key, value = nil)
40
+ key = underscore key
41
+ values = options[key] || []
42
+ options.merge(key => values + [value].compact)
43
+ end
44
+
45
+ def underscore(string)
46
+ string.gsub('-','_')
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ require "map"
2
+
3
+ class MVCLI::Decoding
4
+ def initialize
5
+ @enrichments = Map.new do |h,k|
6
+ h[k] = []
7
+ end
8
+ end
9
+
10
+ def call(name, value, target = Object)
11
+ if target.is_a?(Array)
12
+ [value].flatten.map {|element| call name, element, target.first}
13
+ else
14
+ @enrichments[name].reduce value do |value, enrichment|
15
+ enrichment.call value
16
+ end
17
+ end
18
+ end
19
+
20
+ def method_missing(name, &block)
21
+ fail "must supply a block to transform value named '#{name}'" unless block
22
+ @enrichments[name] << block
23
+ return self
24
+ end
25
+ end
@@ -0,0 +1,72 @@
1
+ require "mvcli/form"
2
+ require "active_support/inflector/methods"
3
+
4
+ class MVCLI::Form::Input
5
+ def initialize(name, target, options = {}, &block)
6
+ @decoders = []
7
+ @handler = handler(target).new name, target, options, &block
8
+ end
9
+
10
+ def decode(&block)
11
+ @handler.decode &block
12
+ return self
13
+ end
14
+
15
+ def value(source, context = nil)
16
+ @handler.value source, context
17
+ end
18
+
19
+ def handler(target)
20
+ target.is_a?(Array) ? ListTarget : Target
21
+ end
22
+
23
+ class Target
24
+ def initialize(name, target, options = {}, &block)
25
+ @name, @options = name, Map(options)
26
+ @decoders = []
27
+ if block_given?
28
+ @decoders << block
29
+ end
30
+ end
31
+
32
+ def decode(&block)
33
+ @decoders << block
34
+ end
35
+
36
+ def value(source, context = nil)
37
+ if value = [source[@name]].flatten.first
38
+ @decoders.reduce(value) do |value, decoder|
39
+ decoder.call value
40
+ end
41
+ else
42
+ default context
43
+ end
44
+ end
45
+
46
+ def default(context)
47
+ value = @options[:default]
48
+ if value.respond_to?(:call)
49
+ if context
50
+ context.instance_exec(&value)
51
+ else
52
+ value.call
53
+ end
54
+ else
55
+ value
56
+ end
57
+ end
58
+ end
59
+
60
+ class ListTarget < Target
61
+ include ActiveSupport::Inflector
62
+
63
+ def value(source, context = nil)
64
+ source = Map(source)
65
+ list = [source[singularize @name]].compact.flatten.map do |value|
66
+ super({@name => value}, context)
67
+ end.compact
68
+ list.empty? ? [default(context)].compact.flatten : list
69
+ end
70
+ end
71
+
72
+ end
data/lib/mvcli/form.rb ADDED
@@ -0,0 +1,87 @@
1
+ require "mvcli/decoding"
2
+ require "mvcli/validatable"
3
+
4
+ module MVCLI
5
+ class Form
6
+ include MVCLI::Validatable
7
+
8
+ def initialize(params = {}, type = Map)
9
+ @source = params
10
+ @target = type
11
+ end
12
+
13
+ def value
14
+ self.class.output.call self
15
+ end
16
+
17
+ def attributes
18
+ self.class.inputs.reduce(Map.new) do |map, pair|
19
+ name, input = *pair
20
+ map.tap do
21
+ map[name] = input.value @source, self
22
+ end
23
+ end
24
+ end
25
+
26
+ class Decoder
27
+ def initialize(form, names)
28
+ @form, @names = form, names
29
+ end
30
+
31
+ def call(string)
32
+ @form.new Map Hash[@names.zip string.split ':']
33
+ end
34
+
35
+ def to_proc
36
+ proc {|*_| call(*_)}
37
+ end
38
+ end
39
+
40
+ class << self
41
+ attr_accessor :target
42
+ attr_reader :inputs, :output
43
+
44
+ def inherited(base)
45
+ base.class_eval do
46
+ @inputs = Map.new
47
+ end
48
+ end
49
+
50
+ def decoder
51
+ Decoder.new self, inputs.keys
52
+ end
53
+
54
+ def output(&block)
55
+ if block_given?
56
+ @output = block
57
+ else
58
+ @output
59
+ end
60
+ end
61
+
62
+ def input(name, target, options = {}, &block)
63
+ if block_given?
64
+ form = Class.new(MVCLI::Form, &block)
65
+ form.target = [target].flatten.first
66
+ validates_child name
67
+ input = Input.new(name, target, options, &form.decoder)
68
+ else
69
+ input = Input.new(name, target, options, &options[:decode])
70
+ end
71
+ @inputs[name] = input
72
+ if options[:required]
73
+ if target.is_a?(Array)
74
+ validates(name, "cannot be empty", nil: true) {|value| value && !value.empty?}
75
+ else
76
+ validates(name, "is required", nil: true) {|value| !value.nil?}
77
+ end
78
+ end
79
+ define_method(name) do
80
+ input.value @source, self
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ require "mvcli/form/input"
data/lib/mvcli/router.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "map"
2
- require_relative "router/pattern"
2
+ require "mvcli/router/pattern"
3
+ require "mvcli/argv"
3
4
 
4
5
  module MVCLI
5
6
  class Router
@@ -33,7 +34,8 @@ module MVCLI
33
34
  end
34
35
 
35
36
  def match(command)
36
- match = @pattern.match(command.argv)
37
+ argv = MVCLI::Argv.new command.argv
38
+ match = @pattern.match(argv.arguments)
37
39
  if match.matches?
38
40
  proc do |command|
39
41
  action = @actions[@action] or fail "no action found for #{@action}"
@@ -42,9 +44,5 @@ module MVCLI
42
44
  end
43
45
  end
44
46
  end
45
-
46
- class Match
47
-
48
- end
49
47
  end
50
48
  end
@@ -0,0 +1,188 @@
1
+ require "map"
2
+
3
+ module MVCLI::Validatable
4
+
5
+ def self.included(base)
6
+ base.extend ValidationDSL
7
+ end
8
+
9
+ def valid?
10
+ validation.valid?
11
+ end
12
+
13
+ def validate!
14
+ validation.validate!
15
+ end
16
+
17
+ def violations
18
+ validation.violations
19
+ end
20
+
21
+ def validation
22
+ validators.reduce(Validation.new(self)) do |validation, validator|
23
+ validation.tap do
24
+ validator.validate self, validation
25
+ end
26
+ end
27
+ end
28
+
29
+ def validators
30
+ self.class.validators
31
+ end
32
+
33
+ class ValidationError < StandardError
34
+ attr_reader :validation
35
+
36
+ def initialize(validation)
37
+ super validation.to_s
38
+ @validation = validation
39
+ end
40
+
41
+ def violations
42
+ validation.violations
43
+ end
44
+
45
+ def each(&block)
46
+ validation.each(&block)
47
+ end
48
+ end
49
+
50
+ class Validator
51
+ def initialize
52
+ @rules = []
53
+ @children = []
54
+ end
55
+
56
+ def validates(field, message, options = {}, &predicate)
57
+ @rules << Rule.new(field, message, Map(options), predicate)
58
+ end
59
+
60
+ def validates_child(name)
61
+ @children << name
62
+ end
63
+
64
+ def validate(object, validation = Validation.new(object))
65
+ @rules.reduce(validation) do |v, rule|
66
+ v.tap do
67
+ rule.call object, v.violations, v.errors
68
+ end
69
+ end
70
+ @children.each do |name|
71
+ validate_child object, name, validation
72
+ end
73
+ return validation
74
+ end
75
+
76
+ def validate_child(object, name, validation)
77
+ child = object.send(name) || []
78
+ validation.append name, [child].flatten.map(&:validation)
79
+ rescue StandardError => e
80
+ validation.errors[name] << e
81
+ end
82
+ end
83
+
84
+
85
+ class Validation
86
+ attr_reader :object, :violations, :errors
87
+
88
+ def initialize(object)
89
+ @object = object
90
+ @children = Map.new do |h,k|
91
+ h[k] = []
92
+ end
93
+ @violations = Map.new do |h,k|
94
+ h[k] = []
95
+ end
96
+ @errors = Map.new do |h,k|
97
+ h[k] = []
98
+ end
99
+ end
100
+
101
+ def valid?
102
+ violations.empty? && errors.empty? && children_valid?
103
+ end
104
+
105
+ def validate!
106
+ fail ValidationError, self unless valid?
107
+ end
108
+
109
+ def children_valid?
110
+ @children.values.each do |validations|
111
+ return false unless validations.all?(&:valid?)
112
+ end
113
+ return true
114
+ end
115
+
116
+ def [](key)
117
+ @children[key]
118
+ end
119
+
120
+ def each(&block)
121
+ @children.each &block
122
+ end
123
+
124
+ def append(name, validations)
125
+ @children[name] += validations
126
+ end
127
+
128
+ def to_s
129
+ elements = []
130
+ elements << "violations: #{@violations.inspect}" unless @violations.empty?
131
+ elements << "errors: #{@errors.inspect}" unless @errors.empty?
132
+ elements << "nested: #{children_to_s}" unless @children.empty?
133
+ [@object, elements.join(', ')].join ' '
134
+ end
135
+
136
+ def children_to_s
137
+ Hash[@children.keys.zip @children.values.map {|validations| validations.map(&:to_s)}].inspect
138
+ end
139
+ end
140
+
141
+ module ValidationDSL
142
+ def validator
143
+ @validator ||= Validator.new
144
+ end
145
+
146
+ def validators
147
+ ancestors.reduce [] do |validators, base|
148
+ validators.tap do
149
+ validators << base.validator if base.respond_to?(:validator)
150
+ end
151
+ end
152
+ end
153
+
154
+ def validates(field, message, options = {}, &predicate)
155
+ validator.validates field, message, options, &predicate
156
+ end
157
+
158
+ def validates_not(field, message, &predicate)
159
+ validates(field, message) {|*_| !predicate.call(*_)}
160
+ end
161
+
162
+ def validates_child(name)
163
+ validator.validates_child name
164
+ end
165
+ end
166
+
167
+ class Rule
168
+ def initialize(field, message, options, predicate)
169
+ @field, @message, @options, @predicate = field, message, options, predicate
170
+ end
171
+ def call(validatable, violations, errors)
172
+ value, error = read validatable
173
+ if error
174
+ errors[@field] << error
175
+ elsif value.nil?
176
+ return unless !!@options[:nil]
177
+ else
178
+ violations[@field] << @message unless @predicate.call value
179
+ end
180
+ end
181
+
182
+ def read(validatable)
183
+ return validatable.send(@field), nil
184
+ rescue StandardError => e
185
+ return nil, e
186
+ end
187
+ end
188
+ end
data/lib/mvcli/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module MVCLI
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
data/lib/mvcli.rb CHANGED
@@ -1,4 +1,3 @@
1
1
  module MVCLI
2
2
  require "mvcli/version"
3
- require "mvcli/controller"
4
3
  end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+ require "mvcli/argv"
3
+ require "shellwords"
4
+
5
+ describe "ARGV" do
6
+ use_natural_assertions
7
+ Given(:input) {Shellwords.shellsplit "before --one 1 --two=two stuff in the middle --three -f --four --no-five -p 6 --mo money --mo problems --two-word val --two-word-p after"}
8
+ Given(:argv) {MVCLI::Argv.new input, [:three, :f, :five, :two_word_p]}
9
+
10
+ context " options" do
11
+ Given(:options) {argv.options}
12
+ Then {options[:one] == ['1']}
13
+ Then {options[:two] == ['two']}
14
+ Then {options[:three] == [true]}
15
+ Then {options[:f] == [true]}
16
+ Then {options[:four] == []}
17
+ Then {options[:five] == [false]}
18
+ Then {options[:p] == ['6']}
19
+ Then {options[:mo] == ['money', 'problems']}
20
+ Then {options[:two_word] == ['val']}
21
+ Then {options[:two_word_p] == [true]}
22
+ end
23
+ context " aruments" do
24
+ Given(:arguments) {argv.arguments}
25
+ Then {arguments == %w(before stuff in the middle after)}
26
+ end
27
+ end
@@ -0,0 +1,95 @@
1
+ require "spec_helper"
2
+ require "mvcli/form/input"
3
+
4
+ describe "Form Inputs" do
5
+ use_natural_assertions
6
+ Given(:input) {MVCLI::Form::Input.new :field, type, options, &block}
7
+ Given(:type) {Object}
8
+ Given(:options) {{}}
9
+ Given(:block) {nil}
10
+ describe "with an integer type" do
11
+ Given(:type) {Integer}
12
+ context "when accessing a single value" do
13
+ When(:value) {input.value field: 5}
14
+ Then {value == 5}
15
+ end
16
+ context "when accessing an array of values" do
17
+ When(:value) {input.value field: [1,2,3]}
18
+ Then {value == 1}
19
+ end
20
+ context "when accessing a nil value" do
21
+ When(:value) {input.value field: nil}
22
+ Then {value.nil?}
23
+ end
24
+ end
25
+ describe "with a list of integers" do
26
+ Given(:type) {[Integer]}
27
+ context "when accessing an value represented as a single" do
28
+ When(:value) {input.value field: 5}
29
+ Then {value == [5]}
30
+ end
31
+ context "when accessing a value represented as an array" do
32
+ When(:value) {input.value field: [1,2,3]}
33
+ Then {value == [1,2,3]}
34
+ end
35
+ context "when accessing a nil value" do
36
+ When(:value) {input.value field: nil}
37
+ Then {value == []}
38
+ end
39
+ describe "with decoding" do
40
+ Given(:block) {->(s) { Integer s * 2 } }
41
+ context "with singular value" do
42
+ When(:value) {input.value field: '1'}
43
+ Then {value == [11]}
44
+ end
45
+ context "with array value" do
46
+ When(:value) {input.value field: ['1', '2']}
47
+ Then {value == [11,22]}
48
+ end
49
+ context "with a sparse array value" do
50
+ When(:value) {input.value field: ['1', nil, '2']}
51
+ Then {value == [11,22]}
52
+ end
53
+ context "with an empty list" do
54
+ When(:value) {input.value field: []}
55
+ Then {value == []}
56
+ end
57
+ context "with a nil value" do
58
+ When(:value) {input.value field: nil}
59
+ Then {value == []}
60
+ end
61
+ end
62
+ end
63
+ describe "with decoding" do
64
+ Given(:block) { ->(s) { Integer s * 2}}
65
+
66
+ context "when accessed" do
67
+ When(:value) {input.value field: ['1']}
68
+ Then {value == 11}
69
+ end
70
+ context "when accessing a nil value and no default" do
71
+ When(:value) {input.value field: nil}
72
+ Then {value.nil?}
73
+ end
74
+ end
75
+
76
+ describe "with a default" do
77
+ Given(:options) {{default: 5}}
78
+ context "when accesing nil" do
79
+ When(:value) {input.value field: nil}
80
+ Then {value == 5}
81
+ end
82
+ context "when accessing a value" do
83
+ When(:value) {input.value field: 10}
84
+ Then {value == 10}
85
+ end
86
+ end
87
+
88
+ describe "a plural list input" do
89
+ Given(:input) {MVCLI::Form::Input.new :fields, [Integer]}
90
+ context "passing a singular value" do
91
+ When(:value) { input.value field: 10 }
92
+ Then {value == [10]}
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,116 @@
1
+ require "spec_helper"
2
+ require "mvcli/form"
3
+ require "mvcli/decoding"
4
+ require "ipaddr"
5
+
6
+ describe "A form for creating a load balancer" do
7
+ use_natural_assertions
8
+ Given(:definition) do
9
+ Class.new(MVCLI::Form) do
10
+ input :name, String, default: -> {naming.generate 'l', 'b'}
11
+
12
+ input :port, Integer, default: 80, decode: ->(s) {Integer s}
13
+
14
+ input :protocol, String, default: 'HTTP', decode: :upcase
15
+
16
+ input :virtual_ips, [String], default: ['PUBLIC']
17
+
18
+ input :nodes, [Node], required: true do
19
+ input :address, IPAddr, required: true, decode: ->(s) {IPAddr.new s}
20
+ input :port, Integer, default: 80, decode: ->(s) {Integer s}
21
+ input :type, String, default: 'PRIMARY', decode: :upcase
22
+ input :condition, String, default: 'ENABLED', decode: :upcase
23
+
24
+ validates(:port, "port must be between 0 and 65,535") {|port| port >= 0 && port <= 65535}
25
+ validates(:type, "invalid type") {|type| ['PRIMARY', 'SECONDARY'].member? type}
26
+ validates(:condition, "invalid condition") {|c| ['ENABLED', 'DISABLED'].member? c}
27
+ end
28
+ end
29
+ end
30
+ Given(:form) do
31
+ definition.new(params).tap do |f|
32
+ f.stub(:decoders) {MVCLI::Decoding}
33
+ f.stub(:naming) {mock(:NameGenerator, generate: 'random-name')}
34
+ end
35
+ end
36
+ context "with no nodes provided" do
37
+ Given(:params) {({node: []})}
38
+ Then {!form.valid?}
39
+ And {form.violations[:nodes] == ["cannot be empty"]}
40
+
41
+ end
42
+ context "with invalid node inputs" do
43
+ Given(:params) do
44
+ ({
45
+ node: ['10.0.0.1:-500', 'xxx:80']
46
+ })
47
+ end
48
+ Then {!form.valid?}
49
+ context "the first violation" do
50
+ Given(:violations) {form.validation[:nodes].first.violations}
51
+ Then {violations[:port] == ["port must be between 0 and 65,535"]}
52
+ end
53
+ context "the second error" do
54
+ Given(:errors) {form.validation[:nodes].last.errors}
55
+ Then {errors[:address].first.is_a?(IPAddr::InvalidAddressError)}
56
+ end
57
+ end
58
+ context "with partially specified, valid inputs" do
59
+ Given(:params) do
60
+ ({node: ['10.0.0.1:80']})
61
+ end
62
+ Then {form.name == 'random-name'}
63
+ And {form.port == 80}
64
+ And {form.protocol == 'HTTP'}
65
+ And {form.virtual_ips == ['PUBLIC']}
66
+ context "the default form node" do
67
+ Given(:node) {form.nodes.first}
68
+ Then {node.address == IPAddr.new('10.0.0.1')}
69
+ And {node.port == 80}
70
+ end
71
+ end
72
+ context "with fully specified, valid inputs" do
73
+ Given(:params) {
74
+ ({
75
+ name: 'foo',
76
+ port: '80',
77
+ protocol: 'http',
78
+ virtual_ip: ['public', 'servicenet'],
79
+ node: [
80
+ '10.0.0.1:80:primary:enabled',
81
+ '10.0.0.2:80:secondary:disabled'
82
+ ]
83
+ })
84
+ }
85
+ Then {form.valid?}
86
+ And {form.name == 'foo'}
87
+ And {form.port == 80}
88
+ And {form.protocol == 'HTTP'}
89
+ And {form.nodes.length == 2}
90
+ context ". On the first node" do
91
+ Given(:node) {form.nodes.first}
92
+ Then {node.address == IPAddr.new('10.0.0.1')}
93
+ And {node.port == 80}
94
+ And {node.condition == 'ENABLED'}
95
+ And {node.type == 'PRIMARY'}
96
+ end
97
+ context ". On the second node" do
98
+ Given(:node) {form.nodes.last}
99
+ Then {node.address == IPAddr.new('10.0.0.2')}
100
+ And {node.port == 80}
101
+ And {node.condition == 'DISABLED'}
102
+ And {node.type == 'SECONDARY'}
103
+ end
104
+ end
105
+ end
106
+
107
+ class Node
108
+ include MVCLI::Validatable
109
+ attr_accessor :address, :port, :protocol, :condition, :type
110
+ validates(:port, "port must be between 0 and 65,535") {|port| port >= 0 && port <= 65535}
111
+
112
+ def initialize(attrs)
113
+ @address, @port, @protocal, @condition, @type = *attrs.values_at(:address, :port, :protocol, :condition, :type)
114
+ end
115
+
116
+ end
@@ -25,6 +25,12 @@ describe "MVCLI::Router" do
25
25
  Then {@command.argv.should eql ['login']}
26
26
  end
27
27
 
28
+ context "when there are command line options, it does not interfere" do
29
+ Given {router.match 'login' => 'logins#create'}
30
+ When {invoke 'login --then --go-away -f 6 -p'}
31
+ Then {@command.should_not be_nil}
32
+ end
33
+
28
34
  context "with a route matched to a block" do
29
35
  Given {router.match bam: ->(command) {@command = command}}
30
36
  When {invoke 'bam'}
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+ require "mvcli/validatable"
3
+
4
+ describe "a validator" do
5
+ Given(:validator) {MVCLI::Validatable::Validator.new}
6
+ context "when it validates a field that does not exist on the object" do
7
+ Given {validator.validates(:does_not_exist, "invalid") {}}
8
+ When(:validation) {validator.validate(Object.new)}
9
+ Then {validation.errors[:does_not_exist].class < NameError}
10
+ Then {not validation.valid?}
11
+ end
12
+ describe "validating a child" do
13
+ Given {validator.validates_child(:some_child)}
14
+ context "when it is nil" do
15
+ When(:validation) {validator.validate(mock(:Object, :some_child => nil))}
16
+ Then {validation.valid?}
17
+ end
18
+ context "when it does not exist" do
19
+ When(:validation) {validator.validate(Object.new)}
20
+ Then {not validation.errors[:some_child].nil?}
21
+ And {not validation.valid?}
22
+ end
23
+ end
24
+ end
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.6
4
+ version: 0.0.7
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-06-07 00:00:00.000000000 Z
32
+ date: 2013-06-26 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: map
@@ -72,14 +72,16 @@ files:
72
72
  - LICENSE.txt
73
73
  - README.md
74
74
  - Rakefile
75
- - example/controllers/loadbalancers_controller.rb
76
- - example/routes.rb
77
75
  - lib/mvcli.rb
78
76
  - lib/mvcli/actions.rb
79
77
  - lib/mvcli/app.rb
78
+ - lib/mvcli/argv.rb
80
79
  - lib/mvcli/command.rb
81
80
  - lib/mvcli/controller.rb
81
+ - lib/mvcli/decoding.rb
82
82
  - lib/mvcli/erb.rb
83
+ - lib/mvcli/form.rb
84
+ - lib/mvcli/form/input.rb
83
85
  - lib/mvcli/loader.rb
84
86
  - lib/mvcli/middleware.rb
85
87
  - lib/mvcli/middleware/exception_logger.rb
@@ -88,11 +90,15 @@ files:
88
90
  - lib/mvcli/renderer.rb
89
91
  - lib/mvcli/router.rb
90
92
  - lib/mvcli/router/pattern.rb
93
+ - lib/mvcli/validatable.rb
91
94
  - lib/mvcli/version.rb
92
95
  - mvcli.gemspec
93
96
  - spec/mvcli/actions_spec.rb
97
+ - spec/mvcli/argv_spec.rb
94
98
  - spec/mvcli/dummy/app/providers/test_provider.rb
95
99
  - spec/mvcli/erb_spec.rb
100
+ - spec/mvcli/form/input_spec.rb
101
+ - spec/mvcli/form_spec.rb
96
102
  - spec/mvcli/loader_spec.rb
97
103
  - spec/mvcli/middleware/exception_logger_spec.rb
98
104
  - spec/mvcli/middleware/exit_status_spec.rb
@@ -100,6 +106,7 @@ files:
100
106
  - spec/mvcli/provisioning_spec.rb
101
107
  - spec/mvcli/router/pattern_spec.rb
102
108
  - spec/mvcli/router_spec.rb
109
+ - spec/mvcli/validatable_spec.rb
103
110
  - spec/spec_helper.rb
104
111
  homepage: https://github.com/cowboyd/mvcli
105
112
  licenses:
@@ -127,8 +134,11 @@ specification_version: 4
127
134
  summary: Local Apps. Remote Apps. They're all at your fingertips
128
135
  test_files:
129
136
  - spec/mvcli/actions_spec.rb
137
+ - spec/mvcli/argv_spec.rb
130
138
  - spec/mvcli/dummy/app/providers/test_provider.rb
131
139
  - spec/mvcli/erb_spec.rb
140
+ - spec/mvcli/form/input_spec.rb
141
+ - spec/mvcli/form_spec.rb
132
142
  - spec/mvcli/loader_spec.rb
133
143
  - spec/mvcli/middleware/exception_logger_spec.rb
134
144
  - spec/mvcli/middleware/exit_status_spec.rb
@@ -136,4 +146,6 @@ test_files:
136
146
  - spec/mvcli/provisioning_spec.rb
137
147
  - spec/mvcli/router/pattern_spec.rb
138
148
  - spec/mvcli/router_spec.rb
149
+ - spec/mvcli/validatable_spec.rb
139
150
  - spec/spec_helper.rb
151
+ has_rdoc:
@@ -1,10 +0,0 @@
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 DELETED
@@ -1,31 +0,0 @@
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