midas-touch 1.0.0
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 +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +131 -0
- data/Rakefile +10 -0
- data/features/filters.feature +16 -0
- data/features/input_group.feature +26 -0
- data/features/input_representation.feature +28 -0
- data/features/sinatra.feature +54 -0
- data/features/step-definitions/filter_steps.rb +15 -0
- data/features/step-definitions/general_steps.rb +11 -0
- data/features/step-definitions/input_group_steps.rb +68 -0
- data/features/step-definitions/input_steps.rb +60 -0
- data/features/step-definitions/sinatra_steps.rb +53 -0
- data/features/step-definitions/validation_steps.rb +15 -0
- data/features/support/env.rb +27 -0
- data/features/validation.feature +15 -0
- data/lib/midas-touch/filter.rb +16 -0
- data/lib/midas-touch/input.rb +38 -0
- data/lib/midas-touch/input_group.rb +67 -0
- data/lib/midas-touch/validation.rb +16 -0
- data/lib/midas-touch/version.rb +3 -0
- data/lib/midas-touch.rb +36 -0
- data/lib/sinatra/midas-touch/dsl.rb +29 -0
- data/lib/sinatra/midas-touch.rb +16 -0
- data/midas-touch.gemspec +25 -0
- metadata +166 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 46e9074dc53fc0fcc84be15c3b62da210dc60ef1
|
4
|
+
data.tar.gz: f51bf777fa2c077f3655f2773aae8f144ca87404
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b73168f9da024cd3ec38f56c076ec71283542d7ed05aaf9d0bfe838d9764c54a867e7d4dd5087d04d5b8ab103fab407b59a7e064ed617b93f0546ed9455cfe80
|
7
|
+
data.tar.gz: e239e8af613aea11c42c2f8fe0a95f0936f4dbbf2a24645e222ab120c5c2272b86c68adf3c93f04afd9d26dfa0df8c38d6fb94da36ee19889fbd3895b973f53a
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
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
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Darren Coxall
|
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,131 @@
|
|
1
|
+
# Midas Touch
|
2
|
+
|
3
|
+
> Everything I touch turns to gold!
|
4
|
+
|
5
|
+
Midas provides a collection of classes to help manage inputs. The concept is
|
6
|
+
simple. You have a collection of inputs. Those inputs can each have multiple
|
7
|
+
filters as well as multiple validation rules.
|
8
|
+
|
9
|
+
If you choose you can filter and validate the individual inputs or do them all
|
10
|
+
together in a group.
|
11
|
+
|
12
|
+
**Midas provides no pre-created validation or filter rules. I believe everyone
|
13
|
+
should understand the exact way their validations and filters work.**
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
gem 'midas-touch'
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install midas-touch
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
### Sinatra DSL
|
32
|
+
|
33
|
+
#### Classic
|
34
|
+
|
35
|
+
require "sinatra"
|
36
|
+
require "midas-touch"
|
37
|
+
|
38
|
+
post("foo") do
|
39
|
+
form do
|
40
|
+
filters :strip
|
41
|
+
field :first_name, :required
|
42
|
+
field :last_name, :required
|
43
|
+
field :contact, :phone_number
|
44
|
+
end
|
45
|
+
|
46
|
+
if form.valid?
|
47
|
+
# do something
|
48
|
+
else
|
49
|
+
# render the form
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# in foo.html.erb
|
54
|
+
<% if form.error_on?(:first_name) %>
|
55
|
+
First name is required
|
56
|
+
<% end %>
|
57
|
+
<input name="first_name" value="<%= form[:first_name] %>" >
|
58
|
+
|
59
|
+
#### Modular
|
60
|
+
|
61
|
+
require "sinatra/base"
|
62
|
+
require "midas-touch"
|
63
|
+
|
64
|
+
class Application < Sinatra::Base
|
65
|
+
helpers Sinatra::MidasTouch
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
#### Creating filters
|
70
|
+
|
71
|
+
class StripFilter < MidasTouch::Filter
|
72
|
+
def call(value)
|
73
|
+
value.respond_to?(:strip) ? value.strip : value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Register filter for Sinatra DSL
|
78
|
+
MidasTouch.register_filter(StripFilter.new(:strip))
|
79
|
+
|
80
|
+
#### Creating validators
|
81
|
+
|
82
|
+
class PositiveNumberValidator < MidasTouch::Validation
|
83
|
+
def call(value)
|
84
|
+
value.to_f > 0
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Register validation for Sinatra DSL
|
89
|
+
MidasTouch.register_validation(PositiveNumberValidator.new(:positive))
|
90
|
+
|
91
|
+
#### Using inputs
|
92
|
+
|
93
|
+
first_name = MidasTouch::Input.new(:first_name)
|
94
|
+
first_name.filters << MidasTouch.find_filter(:strip)
|
95
|
+
first_name.validations << MidasTouch.find_validator(:positive)
|
96
|
+
first_name.value = " Darren Coxall "
|
97
|
+
|
98
|
+
# filter
|
99
|
+
first_name.filter! # => "Darren Coxall"
|
100
|
+
|
101
|
+
# validate
|
102
|
+
first_name.valid? # => false
|
103
|
+
|
104
|
+
#### Using groups
|
105
|
+
|
106
|
+
form = MidasTouch::InputGroup.new
|
107
|
+
form.inputs << first_name # first_name is MidasTouch::Input instance
|
108
|
+
|
109
|
+
# form wide filtering
|
110
|
+
form.filters << MidasTouch.find_filter(:strip)
|
111
|
+
form.filter!
|
112
|
+
|
113
|
+
# validation
|
114
|
+
form.valid? # => false
|
115
|
+
|
116
|
+
#### Accessing values
|
117
|
+
|
118
|
+
# form = MidasTouch::InputGroup.new
|
119
|
+
form[:first_name] # => "Darren Coxall"
|
120
|
+
form[:unknown] # => nil
|
121
|
+
|
122
|
+
# Finding the input object
|
123
|
+
form.input(:first_name) # => MidasTouch::Input
|
124
|
+
|
125
|
+
## Contributing
|
126
|
+
|
127
|
+
All contributions should be tested using Cucumber. To run the test suite do the
|
128
|
+
following:
|
129
|
+
|
130
|
+
$ bundle install
|
131
|
+
$ bundle exec rake
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Feature: Filter logic
|
2
|
+
|
3
|
+
In order to easily filter inputs (strip whitespace, upcase, etc)
|
4
|
+
then we require the ability to define filters that can be executed
|
5
|
+
on values.
|
6
|
+
|
7
|
+
Scenario: Use of the base filter class
|
8
|
+
Given I wish to create a new filter
|
9
|
+
When I create a sub-class of "MidasTouch::Filter"
|
10
|
+
Then the class can be initialized with a name
|
11
|
+
And responds to the call method
|
12
|
+
|
13
|
+
Scenario: Registering filters for easy access
|
14
|
+
Given I have a Filter
|
15
|
+
When I register it with MidasTouch
|
16
|
+
Then I can retrieve it by name
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Feature: Handling collections of input
|
2
|
+
|
3
|
+
We can handle collections of inputs easily via the use
|
4
|
+
of an InputGroup which allows us to filter and validate
|
5
|
+
numerous inputs.
|
6
|
+
|
7
|
+
Scenario: Adding inputs to a group
|
8
|
+
Given I have an InputGroup
|
9
|
+
Then I can add inputs
|
10
|
+
|
11
|
+
Scenario: Adding group filters
|
12
|
+
Given I have an InputGroup
|
13
|
+
And it has a Filter
|
14
|
+
When it is filtered
|
15
|
+
Then all inputs are filtered
|
16
|
+
|
17
|
+
Scenario: Adding group validations
|
18
|
+
Given I have an InputGroup
|
19
|
+
And it has a validation rule
|
20
|
+
When it is validated
|
21
|
+
Then all inputs are validated
|
22
|
+
|
23
|
+
Scenario: Enumerate over values
|
24
|
+
Given I have an InputGroup
|
25
|
+
And it has inputs
|
26
|
+
Then I can iterate over the names and values
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Feature: Input Representation
|
2
|
+
|
3
|
+
In order to provide an Object Orientated approach to
|
4
|
+
input cleansing and validation, inputs must be
|
5
|
+
representable as objects within Midas.
|
6
|
+
|
7
|
+
Scenario: Creating a new Input
|
8
|
+
Given I wish to create an input
|
9
|
+
Then I can create one by calling "MidasTouch::Input.new(:name)"
|
10
|
+
And it will be named "name"
|
11
|
+
|
12
|
+
Scenario: Setting an inputs value
|
13
|
+
Given I have an Input
|
14
|
+
Then I can set the value
|
15
|
+
|
16
|
+
Scenario: Adding filters to an input
|
17
|
+
Given I have an Input
|
18
|
+
When I add a filter
|
19
|
+
Then the input can be filtered
|
20
|
+
|
21
|
+
Scenario: Adding validation rules to an input
|
22
|
+
Given I have an Input
|
23
|
+
When I add a validation rule
|
24
|
+
Then the input can be validated
|
25
|
+
|
26
|
+
Scenario: Manually invalidating an input
|
27
|
+
Given I have an Input
|
28
|
+
Then I can manually mark it as invalid
|
@@ -0,0 +1,54 @@
|
|
1
|
+
Feature: Extending Sinatra applications
|
2
|
+
|
3
|
+
The Midas gem provides a DSL for Sinatra based applications
|
4
|
+
allowing them to define inputs and rules with more ease.
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given there is a filter called "strip"
|
8
|
+
And there is a validation called "duck_only"
|
9
|
+
And the following application:
|
10
|
+
"""
|
11
|
+
helpers Sinatra::MidasTouch
|
12
|
+
get('/form') do
|
13
|
+
form do
|
14
|
+
filters :strip
|
15
|
+
field :first_name
|
16
|
+
field :last_name
|
17
|
+
end
|
18
|
+
form.inputs.map { |input|
|
19
|
+
input.name.to_s + ' : ' + (input.value or 'nil')
|
20
|
+
}.join(',')
|
21
|
+
end
|
22
|
+
|
23
|
+
get('/validate') do
|
24
|
+
form do
|
25
|
+
field :example, :duck_only
|
26
|
+
end
|
27
|
+
form.valid?.inspect
|
28
|
+
end
|
29
|
+
"""
|
30
|
+
|
31
|
+
Scenario: Using the sinatra DSL for inputs (without params)
|
32
|
+
When we make a request to "form"
|
33
|
+
Then the inputs have no value
|
34
|
+
|
35
|
+
Scenario: Using the sinatra DSL for inputs (with params)
|
36
|
+
When we make a request to "form" with the following params:
|
37
|
+
| first_name | foo |
|
38
|
+
| last_name | bar |
|
39
|
+
Then the inputs have values
|
40
|
+
|
41
|
+
Scenario: Using the sinatra DSL for validation (without params)
|
42
|
+
When we make a request to "validate"
|
43
|
+
Then the response body is "false"
|
44
|
+
|
45
|
+
Scenario Outline: Using the sinatra DSL for validation (with params)
|
46
|
+
When we make a request to "validate" with the following params:
|
47
|
+
| example | <param value> |
|
48
|
+
Then the response body is "<result>"
|
49
|
+
|
50
|
+
Examples:
|
51
|
+
| param value | result |
|
52
|
+
| foo | false |
|
53
|
+
| fooduck | false |
|
54
|
+
| duck | true |
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Given(/^I wish to create a new filter$/) do
|
2
|
+
@expected_class = MidasTouch::Filter
|
3
|
+
end
|
4
|
+
|
5
|
+
Given(/^I have a Filter$/) do
|
6
|
+
@filter = MidasTouch::Filter.new(:test)
|
7
|
+
end
|
8
|
+
|
9
|
+
When(/^I register it with MidasTouch$/) do
|
10
|
+
MidasTouch.register_filter(@filter)
|
11
|
+
end
|
12
|
+
|
13
|
+
Then(/^I can retrieve it by name$/) do
|
14
|
+
assert_equal(@filter, MidasTouch.find_filter(:test))
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
When(/^I create a sub\-class of "(.*?)"$/) do |klass|
|
2
|
+
@klass = Class.new(Object.const_get(klass))
|
3
|
+
end
|
4
|
+
|
5
|
+
Then(/^the class can be initialized with a name$/) do
|
6
|
+
@instance = @klass.new(:name)
|
7
|
+
end
|
8
|
+
|
9
|
+
Then(/^responds to the call method$/) do
|
10
|
+
assert_respond_to(@instance, :call)
|
11
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
Given(/^I have an InputGroup$/) do
|
2
|
+
@group = MidasTouch::InputGroup.new
|
3
|
+
end
|
4
|
+
|
5
|
+
Then(/^I can add inputs$/) do
|
6
|
+
@group.inputs << MidasTouch::Input.new(:foo)
|
7
|
+
@group.inputs << MidasTouch::Input.new(:bar)
|
8
|
+
assert_includes(@group.fields, :foo)
|
9
|
+
assert_includes(@group.fields, :bar)
|
10
|
+
end
|
11
|
+
|
12
|
+
And(/^it has a Filter$/) do
|
13
|
+
filter = Class.new(MidasTouch::Filter) do
|
14
|
+
def call(value)
|
15
|
+
value.to_s.upcase
|
16
|
+
end
|
17
|
+
end.new(:upcase)
|
18
|
+
@group.filters << filter
|
19
|
+
end
|
20
|
+
|
21
|
+
When(/^it is filtered$/) do
|
22
|
+
@group.inputs << MidasTouch::Input.new(:foo)
|
23
|
+
@group.inputs << MidasTouch::Input.new(:bar)
|
24
|
+
@group.input(:foo).value = "foo"
|
25
|
+
@group.input(:bar).value = "bar"
|
26
|
+
@group.filter!
|
27
|
+
end
|
28
|
+
|
29
|
+
Then(/^all inputs are filtered$/) do
|
30
|
+
values = @group.inputs.map(&:value)
|
31
|
+
assert_includes(values, "FOO")
|
32
|
+
assert_includes(values, "BAR")
|
33
|
+
end
|
34
|
+
|
35
|
+
And(/^it has a validation rule$/) do
|
36
|
+
validation = Class.new(MidasTouch::Validation) do
|
37
|
+
def call(value)
|
38
|
+
value == "duck"
|
39
|
+
end
|
40
|
+
end.new(:is_duck)
|
41
|
+
@group.validations << validation
|
42
|
+
end
|
43
|
+
|
44
|
+
And(/^it has inputs$/) do
|
45
|
+
@group.inputs << MidasTouch::Input.new(:foo)
|
46
|
+
@group.inputs << MidasTouch::Input.new(:bar)
|
47
|
+
@group.input(:foo).value = "foo"
|
48
|
+
@group.input(:bar).value = "bar"
|
49
|
+
end
|
50
|
+
|
51
|
+
When(/^it is validated$/) do
|
52
|
+
@group.inputs << MidasTouch::Input.new(:bar)
|
53
|
+
@group.inputs << MidasTouch::Input.new(:baz)
|
54
|
+
@group.input(:bar).value = "duck"
|
55
|
+
@group.input(:baz).value = "bar"
|
56
|
+
@result = @group.valid?
|
57
|
+
end
|
58
|
+
|
59
|
+
Then(/^all inputs are validated$/) do
|
60
|
+
refute(@result)
|
61
|
+
assert(@group.error_on?(:baz))
|
62
|
+
end
|
63
|
+
|
64
|
+
Then(/^I can iterate over the names and values$/) do
|
65
|
+
act = Hash[@group.map { |k, v| [k, v] }]
|
66
|
+
exp = { :foo => "foo", :bar => "bar" }
|
67
|
+
assert_equal(exp, act)
|
68
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
Given(/^I wish to create an input$/) do
|
2
|
+
@expected_class = MidasTouch::Input
|
3
|
+
end
|
4
|
+
|
5
|
+
Then(/^I can create one by calling "(.*?)"$/) do |code|
|
6
|
+
@eval_result = eval(code)
|
7
|
+
assert_instance_of(@expected_class, @eval_result)
|
8
|
+
end
|
9
|
+
|
10
|
+
Then(/^it will be named "(.*?)"$/) do |name|
|
11
|
+
assert_equal(name, @eval_result.name.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
Given(/^I have an Input$/) do
|
15
|
+
@input = MidasTouch::Input.new(:example)
|
16
|
+
end
|
17
|
+
|
18
|
+
Then(/^I can set the value$/) do
|
19
|
+
@input.value = "raw input value"
|
20
|
+
assert_equal("raw input value", @input.value)
|
21
|
+
end
|
22
|
+
|
23
|
+
When(/^I add a filter$/) do
|
24
|
+
filter = Class.new(MidasTouch::Filter) do
|
25
|
+
def call(value)
|
26
|
+
value.to_s.upcase
|
27
|
+
end
|
28
|
+
end.new(:example)
|
29
|
+
|
30
|
+
@input.filters << filter
|
31
|
+
end
|
32
|
+
|
33
|
+
When(/^I add a validation rule$/) do
|
34
|
+
rule = Class.new(MidasTouch::Validation) do
|
35
|
+
def call(value)
|
36
|
+
value == "duck"
|
37
|
+
end
|
38
|
+
end.new(:example)
|
39
|
+
|
40
|
+
@input.validations << rule
|
41
|
+
end
|
42
|
+
|
43
|
+
Then(/^the input can be filtered$/) do
|
44
|
+
@input.value = "example"
|
45
|
+
@input.filter!
|
46
|
+
assert_equal("EXAMPLE", @input.value)
|
47
|
+
end
|
48
|
+
|
49
|
+
Then(/^the input can be validated$/) do
|
50
|
+
@input.value = "example"
|
51
|
+
refute(@input.valid?)
|
52
|
+
@input.value = "duck"
|
53
|
+
assert(@input.valid?)
|
54
|
+
end
|
55
|
+
|
56
|
+
Then(/^I can manually mark it as invalid$/) do
|
57
|
+
@input.invalidate!
|
58
|
+
@input.value = "duck"
|
59
|
+
refute(@input.valid?)
|
60
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
Given(/^the following application:$/) do |string|
|
2
|
+
mock_app do
|
3
|
+
class_eval(string)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
Then(/^we have an InputGroup$/) do
|
8
|
+
assert_instance_of(MidasTouch::InputGroup, @result)
|
9
|
+
end
|
10
|
+
|
11
|
+
Given(/^there is a filter called "(.*?)"$/) do |name|
|
12
|
+
filter = ::MidasTouch::Filter.new(name)
|
13
|
+
::MidasTouch.register_filter(filter)
|
14
|
+
end
|
15
|
+
|
16
|
+
Given(/^there is a validation called "(.*?)"$/) do |name|
|
17
|
+
validation = Class.new(::MidasTouch::Validation) do
|
18
|
+
def call(value)
|
19
|
+
value == "duck"
|
20
|
+
end
|
21
|
+
end.new(name)
|
22
|
+
::MidasTouch.register_validation(validation)
|
23
|
+
end
|
24
|
+
|
25
|
+
Then(/^the group has the following inputs:$/) do |table|
|
26
|
+
names = table.raw.flatten
|
27
|
+
@result.inputs.each do |input|
|
28
|
+
assert_includes(names, input.name.to_s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
When(/^we make a request to "(.*?)"$/) do |path|
|
33
|
+
get(path)
|
34
|
+
end
|
35
|
+
|
36
|
+
When(/^we make a request to "(.*?)" with the following params:$/) do |path, params|
|
37
|
+
get(path, @params = params.rows_hash)
|
38
|
+
end
|
39
|
+
|
40
|
+
Then(/^the inputs have no value$/) do
|
41
|
+
last_response.body.split(',').each do |line|
|
42
|
+
assert_match("_name : nil", line)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Then(/^the inputs have values$/) do
|
47
|
+
vals = last_response.body.split(",").map { |line| line.split(' : ') }
|
48
|
+
assert_equal(@params, Hash[vals])
|
49
|
+
end
|
50
|
+
|
51
|
+
Then(/^the response body is "(.*?)"$/) do |body|
|
52
|
+
assert_equal(body, last_response.body)
|
53
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Given(/^I wish to create a validation rule$/) do
|
2
|
+
@expected_class = MidasTouch::Validation
|
3
|
+
end
|
4
|
+
|
5
|
+
Given(/^I have a validation rule$/) do
|
6
|
+
@rule = MidasTouch::Validation.new(:example)
|
7
|
+
end
|
8
|
+
|
9
|
+
When(/^I register the with MidasTouch$/) do
|
10
|
+
MidasTouch.register_validation(@rule)
|
11
|
+
end
|
12
|
+
|
13
|
+
Then(/^it can be retrieved with its name$/) do
|
14
|
+
assert_equal(@rule, MidasTouch.find_validation(:example))
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
lib = File.expand_path("../../../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require "rack/test"
|
5
|
+
require "sinatra/base"
|
6
|
+
require "midas-touch"
|
7
|
+
require "minitest"
|
8
|
+
require "minitest/unit"
|
9
|
+
|
10
|
+
World(MiniTest::Assertions)
|
11
|
+
|
12
|
+
module Midas
|
13
|
+
module TestHelpers
|
14
|
+
def mock_app(&block)
|
15
|
+
@app = Sinatra.new(Sinatra::Base) do
|
16
|
+
class_eval(&block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def app
|
21
|
+
@app ||= Class.new(Sinatra::Base)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
World(Rack::Test::Methods)
|
27
|
+
World(Midas::TestHelpers)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: Validation rule representation
|
2
|
+
|
3
|
+
Validation rules need to be represented as standard objects
|
4
|
+
that can easily be added to inputs.
|
5
|
+
|
6
|
+
Scenario: Creating a validation rule
|
7
|
+
Given I wish to create a validation rule
|
8
|
+
When I create a sub-class of "MidasTouch::Validation"
|
9
|
+
Then the class can be initialized with a name
|
10
|
+
And responds to the call method
|
11
|
+
|
12
|
+
Scenario: Registering validation rules
|
13
|
+
Given I have a validation rule
|
14
|
+
When I register the with MidasTouch
|
15
|
+
Then it can be retrieved with its name
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MidasTouch
|
2
|
+
class Input
|
3
|
+
|
4
|
+
attr_accessor :name
|
5
|
+
private :name=
|
6
|
+
|
7
|
+
attr_accessor :value
|
8
|
+
attr_accessor :filters
|
9
|
+
attr_accessor :validations
|
10
|
+
|
11
|
+
def initialize(name)
|
12
|
+
self.name = name.to_sym
|
13
|
+
self.filters = Array.new
|
14
|
+
self.validations = Array.new
|
15
|
+
@invalidate = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def filter!
|
19
|
+
filters.each do |filter|
|
20
|
+
self.value = filter.call(self.value)
|
21
|
+
end
|
22
|
+
self.value
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid?
|
26
|
+
return false if @invalidate
|
27
|
+
validations.each do |rule|
|
28
|
+
return false if !rule.call(self.value)
|
29
|
+
end
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def invalidate!
|
34
|
+
@invalidate = true
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module MidasTouch
|
2
|
+
class InputGroup
|
3
|
+
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_accessor :inputs
|
7
|
+
attr_accessor :filters
|
8
|
+
attr_accessor :validations
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@inputs = Array.new
|
12
|
+
@filters = Array.new
|
13
|
+
@validations = Array.new
|
14
|
+
@failures = Array.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def input(name)
|
18
|
+
name = name.to_sym
|
19
|
+
@inputs.find { |input| input.name == name }
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](name)
|
23
|
+
input = input(name)
|
24
|
+
input.value if input
|
25
|
+
end
|
26
|
+
|
27
|
+
def filter!
|
28
|
+
@inputs.each do |input|
|
29
|
+
filters.each { |filter| input.value = filter.call(input.value) }
|
30
|
+
input.filter!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def fields
|
35
|
+
@inputs.map(&:name)
|
36
|
+
end
|
37
|
+
alias_method :keys, :fields
|
38
|
+
|
39
|
+
def valid?
|
40
|
+
@failures = Array.new
|
41
|
+
@inputs.each do |input|
|
42
|
+
validations.each do |rule|
|
43
|
+
if !rule.call(input.value)
|
44
|
+
@failures << input
|
45
|
+
break
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@failures << input unless input.valid?
|
49
|
+
end
|
50
|
+
@failures.uniq!
|
51
|
+
@failures.empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def error_on?(name)
|
55
|
+
@failures.include?(input(name))
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_h
|
59
|
+
Hash[@inputs.map { |input| [input.name, input.value] }]
|
60
|
+
end
|
61
|
+
|
62
|
+
def each(&block)
|
63
|
+
to_h.each(&block)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
data/lib/midas-touch.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "midas-touch/version"
|
2
|
+
require "midas-touch/filter"
|
3
|
+
require "midas-touch/validation"
|
4
|
+
require "midas-touch/input"
|
5
|
+
require "midas-touch/input_group"
|
6
|
+
|
7
|
+
module MidasTouch
|
8
|
+
|
9
|
+
@@filters = Hash.new
|
10
|
+
@@validations = Hash.new
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def register_filter(filter)
|
15
|
+
@@filters[filter.name] = filter
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_filter(name)
|
19
|
+
@@filters.fetch(name.to_sym)
|
20
|
+
end
|
21
|
+
|
22
|
+
def register_validation(validation)
|
23
|
+
@@validations[validation.name] = validation
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_validation(name)
|
27
|
+
@@validations.fetch(name.to_sym)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
if self.class.const_defined?(:Sinatra)
|
35
|
+
require "sinatra/midas-touch"
|
36
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module MidasTouch
|
3
|
+
class DSL
|
4
|
+
|
5
|
+
attr_reader :group
|
6
|
+
|
7
|
+
def initialize(params)
|
8
|
+
@params = params
|
9
|
+
@group = ::MidasTouch::InputGroup.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def field(name, *args)
|
13
|
+
input = ::MidasTouch::Input.new(name)
|
14
|
+
args.each do |rule|
|
15
|
+
input.validations << ::MidasTouch.find_validation(rule)
|
16
|
+
end
|
17
|
+
input.value = @params[name]
|
18
|
+
@group.inputs << input
|
19
|
+
end
|
20
|
+
|
21
|
+
def filters(*names)
|
22
|
+
names.each do |name|
|
23
|
+
@group.filters << ::MidasTouch.find_filter(name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'sinatra/midas-touch/dsl'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module MidasTouch
|
5
|
+
def form(&block)
|
6
|
+
if block_given?
|
7
|
+
@form = DSL.new(params)
|
8
|
+
@form.instance_eval(&block)
|
9
|
+
@form.group.filter!
|
10
|
+
end
|
11
|
+
@form.group
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
helpers MidasTouch
|
16
|
+
end
|
data/midas-touch.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'midas-touch/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "midas-touch"
|
7
|
+
spec.version = MidasTouch::VERSION
|
8
|
+
spec.authors = ["Darren Coxall"]
|
9
|
+
spec.email = ["darren@simplybusiness.co.uk"]
|
10
|
+
spec.summary = %q{Turn all your inputs to Gold.}
|
11
|
+
spec.description = %q{Clean and validate your inputs from forms or other areas of your application.}
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
20
|
+
spec.add_development_dependency "rake"
|
21
|
+
spec.add_development_dependency "rack-test"
|
22
|
+
spec.add_development_dependency "cucumber"
|
23
|
+
spec.add_development_dependency "minitest", "~> 5.3.5"
|
24
|
+
spec.add_development_dependency "sinatra"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: midas-touch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Darren Coxall
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rack-test
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: cucumber
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 5.3.5
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 5.3.5
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sinatra
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Clean and validate your inputs from forms or other areas of your application.
|
98
|
+
email:
|
99
|
+
- darren@simplybusiness.co.uk
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- .gitignore
|
105
|
+
- Gemfile
|
106
|
+
- LICENSE.txt
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- features/filters.feature
|
110
|
+
- features/input_group.feature
|
111
|
+
- features/input_representation.feature
|
112
|
+
- features/sinatra.feature
|
113
|
+
- features/step-definitions/filter_steps.rb
|
114
|
+
- features/step-definitions/general_steps.rb
|
115
|
+
- features/step-definitions/input_group_steps.rb
|
116
|
+
- features/step-definitions/input_steps.rb
|
117
|
+
- features/step-definitions/sinatra_steps.rb
|
118
|
+
- features/step-definitions/validation_steps.rb
|
119
|
+
- features/support/env.rb
|
120
|
+
- features/validation.feature
|
121
|
+
- lib/midas-touch.rb
|
122
|
+
- lib/midas-touch/filter.rb
|
123
|
+
- lib/midas-touch/input.rb
|
124
|
+
- lib/midas-touch/input_group.rb
|
125
|
+
- lib/midas-touch/validation.rb
|
126
|
+
- lib/midas-touch/version.rb
|
127
|
+
- lib/sinatra/midas-touch.rb
|
128
|
+
- lib/sinatra/midas-touch/dsl.rb
|
129
|
+
- midas-touch.gemspec
|
130
|
+
homepage:
|
131
|
+
licenses:
|
132
|
+
- MIT
|
133
|
+
metadata: {}
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - '>='
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
requirements: []
|
149
|
+
rubyforge_project:
|
150
|
+
rubygems_version: 2.0.14
|
151
|
+
signing_key:
|
152
|
+
specification_version: 4
|
153
|
+
summary: Turn all your inputs to Gold.
|
154
|
+
test_files:
|
155
|
+
- features/filters.feature
|
156
|
+
- features/input_group.feature
|
157
|
+
- features/input_representation.feature
|
158
|
+
- features/sinatra.feature
|
159
|
+
- features/step-definitions/filter_steps.rb
|
160
|
+
- features/step-definitions/general_steps.rb
|
161
|
+
- features/step-definitions/input_group_steps.rb
|
162
|
+
- features/step-definitions/input_steps.rb
|
163
|
+
- features/step-definitions/sinatra_steps.rb
|
164
|
+
- features/step-definitions/validation_steps.rb
|
165
|
+
- features/support/env.rb
|
166
|
+
- features/validation.feature
|