bureaucrat 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +22 -0
- data/README.md +124 -0
- data/lib/bureaucrat/fields.rb +461 -0
- data/lib/bureaucrat/forms.rb +346 -0
- data/lib/bureaucrat/formsets.rb +256 -0
- data/lib/bureaucrat/quickfields.rb +59 -0
- data/lib/bureaucrat/utils.rb +84 -0
- data/lib/bureaucrat/validation.rb +130 -0
- data/lib/bureaucrat/validation_old.rb +148 -0
- data/lib/bureaucrat/widgets.rb +397 -0
- data/lib/bureaucrat/wizard.rb +220 -0
- data/lib/bureaucrat.rb +10 -0
- data/test/fields_test.rb +577 -0
- data/test/forms_test.rb +131 -0
- data/test/formsets_test.rb +51 -0
- data/test/test_helper.rb +22 -0
- data/test/widgets_test.rb +328 -0
- metadata +71 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
module Bureaucrat
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
module SafeData
|
5
|
+
end
|
6
|
+
|
7
|
+
class SafeString < String
|
8
|
+
include SafeData
|
9
|
+
|
10
|
+
def +(rhs)
|
11
|
+
rhs.is_a?(SafeString) ? SafeString.new(super(rhs)) : super(rhs)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Dumb implementation that is good enough for Forms
|
16
|
+
class OrderedHash < Hash
|
17
|
+
def initialize
|
18
|
+
super()
|
19
|
+
@ordered_keys = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def []=(key, value)
|
23
|
+
super(key, value)
|
24
|
+
@ordered_keys << key unless @ordered_keys.include?(key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def each
|
28
|
+
@ordered_keys.each do |key|
|
29
|
+
yield key, self[key]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize_copy(original)
|
34
|
+
super(original)
|
35
|
+
@ordered_keys = original.instance_eval('@ordered_keys').dup
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module_function
|
40
|
+
|
41
|
+
def mark_safe(s)
|
42
|
+
s.is_a?(SafeData) ? s : SafeString.new(s.to_s)
|
43
|
+
end
|
44
|
+
|
45
|
+
ESCAPES = {
|
46
|
+
'&' => '&',
|
47
|
+
'<' => '<',
|
48
|
+
'>' => '>',
|
49
|
+
'"' => '"',
|
50
|
+
"'" => '''
|
51
|
+
}
|
52
|
+
def escape(html)
|
53
|
+
mark_safe(html.gsub(/[&<>"']/) {|match| ESCAPES[match]})
|
54
|
+
end
|
55
|
+
|
56
|
+
def conditional_escape(html)
|
57
|
+
html.is_a?(SafeData) ? html : escape(html)
|
58
|
+
end
|
59
|
+
|
60
|
+
def flatatt(attrs)
|
61
|
+
attrs.map {|k, v| " #{k}=\"#{conditional_escape(v)}\""}.join('')
|
62
|
+
end
|
63
|
+
|
64
|
+
def format_string(string, values)
|
65
|
+
output = string.dup
|
66
|
+
values.each_pair do |variable, value|
|
67
|
+
output.gsub!(/%\(#{variable}\)s/, value.to_s)
|
68
|
+
end
|
69
|
+
output
|
70
|
+
end
|
71
|
+
|
72
|
+
def pretty_name(name)
|
73
|
+
name.to_s.capitalize.gsub(/_/, ' ')
|
74
|
+
end
|
75
|
+
|
76
|
+
def make_float(value)
|
77
|
+
value += '0' if value.is_a?(String) && value != '.' && value[-1,1] == '.'
|
78
|
+
Float(value)
|
79
|
+
end
|
80
|
+
|
81
|
+
def make_bool(value)
|
82
|
+
!(value.respond_to?(:empty?) ? value.empty? : [0, nil, false].include?(value))
|
83
|
+
end
|
84
|
+
end; end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'bureaucrat/utils'
|
2
|
+
|
3
|
+
module Bureaucrat
|
4
|
+
module Validation
|
5
|
+
|
6
|
+
class ValidationError < Exception
|
7
|
+
attr_reader :error_code, :parameters
|
8
|
+
|
9
|
+
def initialize(error_code, parameters=nil)
|
10
|
+
@error_code = error_code
|
11
|
+
@parameters = parameters || {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Validates
|
16
|
+
module_function
|
17
|
+
def fail_with(error_code, parameters=nil)
|
18
|
+
raise ValidationError.new(error_code, parameters)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Converters
|
23
|
+
include Validates
|
24
|
+
|
25
|
+
module_function
|
26
|
+
|
27
|
+
def to_integer(string)
|
28
|
+
Integer(string)
|
29
|
+
rescue ArgumentError
|
30
|
+
fail_with(:invalid)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_float(string)
|
34
|
+
Utils.make_float(string)
|
35
|
+
rescue ArgumentError
|
36
|
+
fail_with(:invalid)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_big_decimal(string)
|
40
|
+
Utils.make_float(string)
|
41
|
+
BigDecimal.new(string)
|
42
|
+
rescue ArgumentError
|
43
|
+
fail_with(:invalid)
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_bool(string)
|
47
|
+
['false', '0'].include?(string) ? false : Utils.make_bool(string)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module Validators
|
52
|
+
include Validates
|
53
|
+
|
54
|
+
module_function
|
55
|
+
|
56
|
+
def empty_value?(value)
|
57
|
+
value.nil? || value == ''
|
58
|
+
end
|
59
|
+
|
60
|
+
def is_present(value)
|
61
|
+
fail_with(:required) if empty_value?(value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def not_empty(value)
|
65
|
+
fail_with(:required) if value.empty?
|
66
|
+
end
|
67
|
+
|
68
|
+
def is_true(value)
|
69
|
+
fail_with(:required) unless value
|
70
|
+
end
|
71
|
+
|
72
|
+
def is_array(value)
|
73
|
+
fail_with(:invalid_list) unless value.kind_of(Array)
|
74
|
+
end
|
75
|
+
|
76
|
+
def has_min_length(value, min_length)
|
77
|
+
value_length = value.length
|
78
|
+
fail_with(:min_length, :min => min_length,
|
79
|
+
:length => value_length) if value_length < min_length
|
80
|
+
end
|
81
|
+
|
82
|
+
def has_max_length(value, max_length)
|
83
|
+
value_length = value.length
|
84
|
+
fail_with(:max_length, :max => max_length,
|
85
|
+
:length => value_length) if value_length > max_length
|
86
|
+
end
|
87
|
+
|
88
|
+
def is_not_lesser_than(value, min_value)
|
89
|
+
fail_with(:min_value, :min => min_value) if value < min_value
|
90
|
+
end
|
91
|
+
|
92
|
+
def is_not_greater_than(value, max_value)
|
93
|
+
fail_with(:max_value, :max => max_value) if value > max_value
|
94
|
+
end
|
95
|
+
|
96
|
+
def has_max_digits(value, max_digits)
|
97
|
+
sign, alldigits, _, whole_digits = value.split
|
98
|
+
fail_with(:max_digits, :max => max_digits) if alldigits > max_digits
|
99
|
+
end
|
100
|
+
|
101
|
+
def has_max_decimal_places(values, decimal_places)
|
102
|
+
sign, alldigits, _, whole_digits = value.split
|
103
|
+
decimals = alldigits.length - whole_digits
|
104
|
+
fail_with(:max_decimal_places, :max => decimal_places) if
|
105
|
+
decimals > decimal_places
|
106
|
+
end
|
107
|
+
|
108
|
+
def has_max_whole_digits(value, max_digits)
|
109
|
+
sign, alldigits, _, whole_digits = value.split
|
110
|
+
fail_with(:max_digits, :max => max_digits) if alldigits > max_digits
|
111
|
+
end
|
112
|
+
|
113
|
+
def included_in(value, collection)
|
114
|
+
fail_with(:not_included, :collection => collection) unless
|
115
|
+
collection.include?(value)
|
116
|
+
end
|
117
|
+
|
118
|
+
def matches_regex(value, regex, error_code=:invalid)
|
119
|
+
fail_with(error_code, :regex => regex) if regex !~ value
|
120
|
+
end
|
121
|
+
|
122
|
+
EMAIL_RE = /(^[-!#\$%&'*+\/=?^_`{}|~0-9A-Z]+(\.[-!#\$%&'*+\/=?^_`{}|~0-9A-Z]+)*|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*")@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$/i
|
123
|
+
|
124
|
+
def is_email(value)
|
125
|
+
matches_regex(value, EMAIL_RE)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module ValueValidator
|
2
|
+
def initialize_vv(format_validator, adaptor, value_validator)
|
3
|
+
@vv_format_validator = format_validator
|
4
|
+
@vv_adaptor = adaptor
|
5
|
+
@vv_value_validator = value_validator
|
6
|
+
end
|
7
|
+
|
8
|
+
# add_format_validator
|
9
|
+
# add_value_validator
|
10
|
+
|
11
|
+
def clean(value, all_values={}, object=nil)
|
12
|
+
return if @vv_format_validator.validate(value, all_values, object)
|
13
|
+
@vv_value_validator.validate(@vv_adaptor.call(value), all_values, object)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Adaptors
|
18
|
+
class Adaptor
|
19
|
+
include Validates
|
20
|
+
|
21
|
+
def initialize(allow_blank=false)
|
22
|
+
@allow_blank = allow_blank
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_object(value)
|
26
|
+
if blank?(value)
|
27
|
+
fail_with(:blank) unless @allow_blank
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
adapt(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def adapt(value)
|
35
|
+
value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class IntegerAdaptor < Adaptor
|
40
|
+
def adapt(value)
|
41
|
+
begin
|
42
|
+
Integer(value)
|
43
|
+
rescue ArgumentError
|
44
|
+
fail_with(:not_integer)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class FloatAdaptor < Adaptor
|
50
|
+
include Bureaucrat::Utils
|
51
|
+
|
52
|
+
def adapt(value)
|
53
|
+
begin
|
54
|
+
make_float(value)
|
55
|
+
rescue ArgumentError
|
56
|
+
fail_with(:not_float)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
class Validator
|
64
|
+
include Validates
|
65
|
+
|
66
|
+
def initialize(allow_blank=false)
|
67
|
+
@allow_blank = allow_blank
|
68
|
+
end
|
69
|
+
|
70
|
+
def valid?(value, all_values={}, object=nil)
|
71
|
+
validate(value, all_values, object)
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate(value, all_values={}, object=nil)
|
76
|
+
blank?(value) && @allow_blank
|
77
|
+
end
|
78
|
+
|
79
|
+
def blank?(value)
|
80
|
+
value.nil? || value.empty?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class HasMinimumLengthOf < Validator
|
85
|
+
def initialize(min_length)
|
86
|
+
@min_length = min_length
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate(value, all_values={}, object=nil)
|
90
|
+
value_length = value.length
|
91
|
+
fail_with(:min_length,
|
92
|
+
:min_length => @min_length,
|
93
|
+
:value_length => value_length) if value_length < @min_length
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class HasMaximumLengthOf < Validator
|
98
|
+
def initialize(max_length)
|
99
|
+
@max_length = max_length
|
100
|
+
end
|
101
|
+
|
102
|
+
def validate(value, all_values={}, object=nil)
|
103
|
+
value_length = value.length
|
104
|
+
fail_with(:max_length,
|
105
|
+
:max_length => @max_length,
|
106
|
+
:value_length => value_length) if value_length < @max_length
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class IsEqualOrGreaterThan < Validator
|
111
|
+
def initialize(min_value)
|
112
|
+
@min_value = min_value
|
113
|
+
end
|
114
|
+
|
115
|
+
def validate(value, all_values={}, object=nil)
|
116
|
+
fail_with(:less_than, :min_value => @min_value) if value < @min_value
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class IsEqualOrLessThan < Validator
|
121
|
+
def initialize(max_value)
|
122
|
+
@max_value = max_value
|
123
|
+
end
|
124
|
+
|
125
|
+
def validate(value, all_values={}, object=nil)
|
126
|
+
fail_with(:more_than, :max_value => @max_value) if value > @max_value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class MatchesRegex < Validator
|
131
|
+
def initialize(regex, custom_error_code=nil)
|
132
|
+
@regex = regex
|
133
|
+
@custom_error_code = custom_error_code
|
134
|
+
end
|
135
|
+
|
136
|
+
def validate(value, all_values={}, object=nil)
|
137
|
+
fail_with(@custom_error_code || :not_matching_regex,
|
138
|
+
:regex => @regex) if @regex !~ value
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class IsEmail < MatchesRegex
|
143
|
+
EMAIL_RE = /(^[-!#\$%&'*+\/=?^_`{}|~0-9A-Z]+(\.[-!#\$%&'*+\/=?^_`{}|~0-9A-Z]+)*|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*")@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$/i
|
144
|
+
|
145
|
+
def initialize
|
146
|
+
super(EMAIL_RE, :is_not_email)
|
147
|
+
end
|
148
|
+
end
|