mvcli 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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