anodator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +28 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.ja.rdoc +33 -0
  7. data/README.rdoc +41 -0
  8. data/Rakefile +50 -0
  9. data/VERSION +1 -0
  10. data/example/example_01.rb +129 -0
  11. data/lib/anodator/anodator_error.rb +5 -0
  12. data/lib/anodator/check_result.rb +41 -0
  13. data/lib/anodator/checker.rb +58 -0
  14. data/lib/anodator/input_spec.rb +199 -0
  15. data/lib/anodator/input_spec_item.rb +33 -0
  16. data/lib/anodator/message.rb +59 -0
  17. data/lib/anodator/output_spec.rb +164 -0
  18. data/lib/anodator/rule.rb +97 -0
  19. data/lib/anodator/rule_set.rb +52 -0
  20. data/lib/anodator/utils.rb +234 -0
  21. data/lib/anodator/validator/base.rb +168 -0
  22. data/lib/anodator/validator/blank_validator.rb +14 -0
  23. data/lib/anodator/validator/complex_validator.rb +60 -0
  24. data/lib/anodator/validator/configuration_error.rb +8 -0
  25. data/lib/anodator/validator/date_validator.rb +151 -0
  26. data/lib/anodator/validator/format_validator.rb +48 -0
  27. data/lib/anodator/validator/inclusion_validator.rb +21 -0
  28. data/lib/anodator/validator/length_validator.rb +37 -0
  29. data/lib/anodator/validator/numeric_validator.rb +46 -0
  30. data/lib/anodator/validator/presence_validator.rb +14 -0
  31. data/lib/anodator/validator.rb +10 -0
  32. data/lib/anodator.rb +3 -0
  33. data/spec/anodator/check_result_spec.rb +101 -0
  34. data/spec/anodator/checker_spec.rb +273 -0
  35. data/spec/anodator/input_spec_item_spec.rb +100 -0
  36. data/spec/anodator/input_spec_spec.rb +584 -0
  37. data/spec/anodator/message_spec.rb +112 -0
  38. data/spec/anodator/output_spec_spec.rb +355 -0
  39. data/spec/anodator/rule_set_spec.rb +190 -0
  40. data/spec/anodator/rule_spec.rb +169 -0
  41. data/spec/anodator/validator/base_spec.rb +214 -0
  42. data/spec/anodator/validator/blank_validator_spec.rb +52 -0
  43. data/spec/anodator/validator/complex_validator_spec.rb +268 -0
  44. data/spec/anodator/validator/date_validator_spec.rb +350 -0
  45. data/spec/anodator/validator/format_validator_spec.rb +158 -0
  46. data/spec/anodator/validator/inclusion_validator_spec.rb +77 -0
  47. data/spec/anodator/validator/length_validator_spec.rb +236 -0
  48. data/spec/anodator/validator/numeric_validator_spec.rb +468 -0
  49. data/spec/anodator/validator/presence_validator_spec.rb +52 -0
  50. data/spec/anodator/validator_spec.rb +16 -0
  51. data/spec/anodator_spec.rb +2 -0
  52. data/spec/spec_helper.rb +12 -0
  53. metadata +188 -0
@@ -0,0 +1,168 @@
1
+ module Anodator
2
+ module Validator
3
+ # +Validator::Base+ is basic class for validations
4
+ class Base
5
+ # value of target for validation
6
+ @@values = nil
7
+
8
+ # valid option keys
9
+ #
10
+ # :allow_blank options are all available options in Validator.
11
+ # In addition, Validator All you need to consider the case of the blank.
12
+ @valid_option_keys = [:allow_blank, :description]
13
+
14
+ # default options
15
+ #
16
+ # Is used as the initial value was not set when you create a new Validator.
17
+ @default_options = { :allow_blank => false }
18
+
19
+ # target specify value
20
+ attr_reader :target
21
+
22
+ # option values
23
+ attr_reader :options
24
+
25
+ # @@valid_option_keys = [:allow_blank]
26
+
27
+ # class methods
28
+ class << self
29
+ # set and/or get valid option keys
30
+ def valid_option_keys(*option_keys)
31
+ # initialize from superclass
32
+ if @valid_option_keys.nil?
33
+ @valid_option_keys = self.superclass.valid_option_keys
34
+ end
35
+
36
+ unless option_keys.size.zero?
37
+ option_keys.each do |key|
38
+ if @valid_option_keys.include?(key)
39
+ raise ArgumentError.new("Validator already has option for '#{key}'")
40
+ else
41
+ @valid_option_keys << key
42
+ end
43
+ end
44
+ end
45
+
46
+ return @valid_option_keys.dup
47
+ end
48
+
49
+ # set and/or get default options
50
+ def default_options(options = nil)
51
+ # initialize from superclass
52
+ if @default_options.nil?
53
+ @default_options = self.superclass.default_options
54
+ end
55
+
56
+ unless options.nil?
57
+ unless options.is_a? Hash
58
+ raise ArgumentError.new("default_options must call with Hash")
59
+ end
60
+ options.each do |option, default_value|
61
+ if @valid_option_keys.include?(option)
62
+ @default_options[option] = default_value
63
+ else
64
+ raise ArgumentError.new("Unknown option '#{option}'")
65
+ end
66
+ end
67
+ end
68
+
69
+ return @default_options.dup
70
+ end
71
+
72
+ # Set the data to be checked.
73
+ #
74
+ # Data to be checked can be set to any object that responds to [].
75
+ def values=(values)
76
+ if values.respond_to?(:[])
77
+ @@values = values
78
+ else
79
+ raise ArgumentError.new("values must be respond to [] method for validations.")
80
+ end
81
+ end
82
+
83
+ # Get the data to be checked
84
+ def values
85
+ return @@values
86
+ end
87
+ end
88
+
89
+ # initializer
90
+ #
91
+ # Specify +options+ as an additional parameter to hold the verification
92
+ # and other options for specifying the +target_expression+ be verified.
93
+ # The default options are optional and will be an empty hash.
94
+ # Key to use additional parameters are stored in class variable
95
+ # +valid_option_keys+.
96
+ # If necessary add additional parameters for the new validator is defined
97
+ # in the inherited class to add.
98
+ def initialize(target_expression, options = { })
99
+ if target_expression.to_s.length.zero?
100
+ raise ArgumentError.new("target cannot be nil or blank")
101
+ else
102
+ @target = target_expression.to_s
103
+ end
104
+ @options = { }
105
+ merge_options!(self.class.default_options)
106
+ merge_options!(options)
107
+ end
108
+
109
+ # validation method
110
+ #
111
+ # +validate+ method must be defined in a class that inherits.
112
+ # In the +validate+ method implements the verification method.
113
+ # Can be implemented to return a boolean value to the final,
114
+ # +valid?+ The method used is called.
115
+ def validate
116
+ raise NoMethodError.new("must define method 'validate'")
117
+ end
118
+
119
+ # Call the +validate+ method to return a boolean value accordingly
120
+ #
121
+ # If any exception occurs in the +validate+ method displays the contents
122
+ # to standard error. Then raise same error.
123
+ def valid?
124
+ return validate
125
+ end
126
+
127
+ # merge options
128
+ #
129
+ # If the key parameter is illegal to throw an ArgumentError.
130
+ def merge_options!(options)
131
+ options.each do |key, value|
132
+ if self.class.valid_option_keys.include?(key)
133
+ @options[key] = value
134
+ else
135
+ raise ArgumentError.new("Unknown option key '#{key}'.")
136
+ end
137
+ end
138
+ end
139
+
140
+ private :merge_options!
141
+
142
+ # target_value
143
+ #
144
+ # always return String object use to_s method
145
+ def target_value
146
+ return @@values[target].to_s
147
+ end
148
+
149
+ def allow_blank?
150
+ return @options[:allow_blank]
151
+ end
152
+
153
+ def description
154
+ return @options[:description]
155
+ end
156
+
157
+ def to_s(level = 4, step = 2)
158
+ (" " * level) + "- #{self.class}(#{self.description})"
159
+ end
160
+
161
+ def validate_configuration
162
+ @@values.spec_item_by_expression(@target)
163
+ rescue UnknownTargetExpressionError => e
164
+ raise InvalidConfiguration.new(e.to_s)
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,14 @@
1
+ require "anodator/validator/base"
2
+
3
+ module Anodator
4
+ module Validator
5
+ # blank validator
6
+ #
7
+ # This is the Validator to validate whether the value is not present.
8
+ class BlankValidator < Base
9
+ def validate
10
+ return target_value.split(//).size.zero?
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,60 @@
1
+ require "anodator/validator/configuration_error"
2
+
3
+ module Anodator
4
+ module Validator
5
+ # ComplexValidator behaves like a single Validator what contains multiple
6
+ # Validators.
7
+ class ComplexValidator < Base
8
+ # Combine logical OR of each Validators
9
+ LOGIC_OR = "OR"
10
+ # Combine logical AND of each Validators
11
+ LOGIC_AND = "AND"
12
+
13
+ valid_option_keys :validators, :logic
14
+ default_options :logic => LOGIC_AND
15
+
16
+ def initialize(options = { })
17
+ super("dummy", options)
18
+ end
19
+
20
+ def validate
21
+ if @options[:validators].nil?
22
+ raise ConfigurationError.new("ComplexValidator must have validators option")
23
+ end
24
+ case @options[:logic]
25
+ when LOGIC_OR
26
+ @options[:validators].each do |validator|
27
+ return true if validator.valid?
28
+ end
29
+ return false
30
+ when LOGIC_AND
31
+ @options[:validators].each do |validator|
32
+ return false unless validator.valid?
33
+ end
34
+ return true
35
+ else
36
+ raise ConfigurationError.new("Unknown logic option '#{@options[:logic]}")
37
+ end
38
+ end
39
+
40
+ def logic_expression
41
+ if @options[:logic] == LOGIC_OR
42
+ return "OR"
43
+ elsif @options[:logic] == LOGIC_AND
44
+ return "AND"
45
+ end
46
+ end
47
+
48
+ def validate_configuration
49
+ # target check skip
50
+ end
51
+
52
+ def to_s(level = 2, step = 2)
53
+ buf = "#{super(level, step)} LOGIC: #{logic_expression}\n"
54
+ buf += @options[:validators].map { |validator|
55
+ validator.to_s(level + step, step)
56
+ }.join("\n")
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,8 @@
1
+ require "anodator/anodator_error"
2
+
3
+ module Anodator
4
+ module Validator
5
+ class ConfigurationError < AnodatorError; end
6
+ end
7
+ end
8
+
@@ -0,0 +1,151 @@
1
+ require "anodator/validator/base"
2
+ require "date"
3
+
4
+ module Anodator
5
+ module Validator
6
+ class DateValidator < Base
7
+ FORMAT_SCANNER_REGEXP = /((YY(?:YY)?)|(M(?![YMD]))|(MM)|(D(?![YMD]))|(DD))/
8
+
9
+ valid_option_keys :from, :to, :format, :base_year
10
+ default_options :format => "YYYY-MM-DD", :base_year => 2000
11
+
12
+ def initialize(target_expression, options = { })
13
+ super(target_expression, options)
14
+
15
+ # format check
16
+ date_regexp_holders
17
+
18
+ if !@options[:from].nil? && !@options[:from].is_a?(Date)
19
+ date = parse_date(@options[:from].to_s)
20
+ if date.nil?
21
+ raise ArgumentError.new("Invalid date expression '#{@options[:from]}'")
22
+ else
23
+ @options[:from] = date
24
+ end
25
+ end
26
+
27
+ if !@options[:to].nil? && !@options[:to].is_a?(Date)
28
+ date = parse_date(@options[:to].to_s)
29
+ if date.nil?
30
+ raise ArgumentError.new("Invalid date expression '#{@options[:to]}'")
31
+ else
32
+ @options[:to] = date
33
+ end
34
+ end
35
+ end
36
+
37
+ def validate
38
+ if allow_blank?
39
+ return true if target_value.split(//).size.zero?
40
+ end
41
+
42
+
43
+ begin
44
+ # check format
45
+ return false unless date = parse_date(target_value)
46
+
47
+ @options.each do |option, configuration|
48
+ case option
49
+ when :from
50
+ return false if configuration > date
51
+ when :to
52
+ return false if configuration < date
53
+ end
54
+ end
55
+
56
+ return true
57
+ rescue ArgumentError
58
+ # invalid date expression
59
+ return false
60
+ end
61
+ end
62
+
63
+ def from
64
+ if @options[:from]
65
+ return @options[:from].dup
66
+ else
67
+ return nil
68
+ end
69
+ end
70
+
71
+ def to
72
+ if @options[:to]
73
+ return @options[:to].dup
74
+ else
75
+ return nil
76
+ end
77
+ end
78
+
79
+ def format
80
+ return @options[:format].dup
81
+ end
82
+
83
+ # parse string with :format option
84
+ #
85
+ # not matched return nil
86
+ def parse_date(date_expression)
87
+ return nil unless match_data = date_regexp.match(date_expression)
88
+
89
+ index = 0
90
+ date_hash = date_regexp_holders.inject({ }) do |hash, key|
91
+ index += 1
92
+ hash[key] = match_data[index].to_i
93
+
94
+ next hash
95
+ end
96
+ # for short year
97
+ if date_hash.keys.include?(:short_year)
98
+ date_hash[:year] = @options[:base_year].to_i + date_hash[:short_year]
99
+ end
100
+
101
+ return Date.new(date_hash[:year], date_hash[:month], date_hash[:day])
102
+ end
103
+ private :parse_date
104
+
105
+ def date_regexp
106
+ date_regexp_holders # check format string
107
+
108
+ regexp_string = @options[:format].dup
109
+ regexp_string.sub!(/YYYY/, '(\d{4})')
110
+ regexp_string.sub!(/YY/, '(\d{2})')
111
+ regexp_string.sub!(/MM/, '(\d{2})')
112
+ regexp_string.sub!(/M/, '(\d{1,2})')
113
+ regexp_string.sub!(/DD/, '(\d{2})')
114
+ regexp_string.sub!(/D/, '(\d{1,2})')
115
+
116
+ return Regexp.new("^#{regexp_string}$")
117
+ end
118
+ private :date_regexp
119
+
120
+ def date_regexp_holders
121
+ scans = @options[:format].scan FORMAT_SCANNER_REGEXP
122
+ year_count, month_count, day_count = 0, 0, 0
123
+ holders = scans.map do |scan|
124
+ case scan.first
125
+ when "YYYY"
126
+ year_count += 1
127
+ :year
128
+ when "YY"
129
+ year_count += 1
130
+ :short_year
131
+ when "MM", "M"
132
+ month_count += 1
133
+ :month
134
+ when "DD", "D"
135
+ day_count += 1
136
+ :day
137
+ end
138
+ end
139
+ unless holders.size == 3
140
+ raise ArgumentError.new("date format must be contained year(YYYY or YY), month(MM or M) and day(DD or D).")
141
+ end
142
+ unless year_count == 1 && month_count == 1 && day_count == 1
143
+ raise ArgumentError.new("date format must be contained year(YYYY or YY), month(MM or M) and day(DD or D).")
144
+ end
145
+
146
+ return holders
147
+ end
148
+ private :date_regexp_holders
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,48 @@
1
+ require "anodator/validator/base"
2
+ require "anodator/validator/configuration_error"
3
+
4
+ module Anodator
5
+ module Validator
6
+ class FormatValidator < Base
7
+ ALL_ZENKAKU_REGEXP = /(?:\xEF\xBD[\xA1-\xBF]|\xEF\xBE[\x80-\x9F])|[\x20-\x7E]/
8
+
9
+ valid_option_keys :format, :all_zenkaku
10
+ default_options :all_zenkaku => false
11
+
12
+ def initialize(target_expression, options = { })
13
+ super(target_expression, options)
14
+
15
+ if @options[:format].is_a? String
16
+ @options[:format] = Regexp.new("#{@options[:format]}")
17
+ end
18
+ end
19
+
20
+ def validate
21
+ if target_value.split(//).size.zero?
22
+ if allow_blank?
23
+ return true
24
+ end
25
+ end
26
+
27
+
28
+ if @options[:all_zenkaku]
29
+ return target_value !~ ALL_ZENKAKU_REGEXP
30
+ else
31
+ unless @options[:format].is_a? Regexp
32
+ raise ConfigurationError.new(":format option must be Regexp object")
33
+ end
34
+
35
+ if @options[:format].match target_value
36
+ return true
37
+ else
38
+ return false
39
+ end
40
+ end
41
+ end
42
+
43
+ def format
44
+ return @options[:format].dup
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ require "anodator/validator/base"
2
+
3
+ module Anodator
4
+ module Validator
5
+ class InclusionValidator < Base
6
+ valid_option_keys :in
7
+
8
+ def validate
9
+ if allow_blank?
10
+ return true if target_value.split(//).size.zero?
11
+ end
12
+
13
+ unless @options[:in].respond_to? :include?
14
+ raise ConfigurationError.new(":in option must be responed_to include?")
15
+ end
16
+
17
+ return @options[:in].include?(target_value)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ require "anodator/validator/base"
2
+ require "anodator/validator/configuration_error"
3
+
4
+ module Anodator
5
+ module Validator
6
+ class LengthValidator < Base
7
+ valid_option_keys :in, :maximum, :minimum, :is
8
+
9
+ def validate
10
+ length = target_value.split(//).size
11
+
12
+ if allow_blank?
13
+ return true if length.zero?
14
+ end
15
+
16
+ @options.each do |option, configuration|
17
+ case option
18
+ when :in
19
+ if configuration.is_a? Range
20
+ return false unless configuration.include?(length)
21
+ else
22
+ raise ConfigurationError.new(":in option value must be Range object")
23
+ end
24
+ when :maximum
25
+ return false if length > configuration.to_i
26
+ when :minimum
27
+ return false if length < configuration.to_i
28
+ when :is
29
+ return false if length != configuration.to_i
30
+ end
31
+ end
32
+
33
+ return true
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,46 @@
1
+ require "anodator/validator/base"
2
+ require "bigdecimal"
3
+
4
+ module Anodator
5
+ module Validator
6
+ class NumericValidator < Base
7
+ valid_option_keys :only_integer, :greater_than, :greater_than_or_equal_to
8
+ valid_option_keys :less_than, :less_than_or_equal_to, :equal_to
9
+ default_options :only_integer => false
10
+
11
+ def validate
12
+ if allow_blank?
13
+ return true if target_value.split(//).size.zero?
14
+ end
15
+
16
+ # check format
17
+ if @options[:only_integer]
18
+ regexp = /^-?\d+$/
19
+ else
20
+ regexp = /^-?\d+(\.\d+)?$/
21
+ end
22
+ return false unless regexp.match target_value
23
+
24
+ # convert BigDecimal value
25
+ value = BigDecimal.new(target_value)
26
+
27
+ @options.each do |option, configuration|
28
+ case option
29
+ when :greater_than
30
+ return false unless value > BigDecimal.new(configuration.to_s)
31
+ when :greater_than_or_equal_to
32
+ return false unless value >= BigDecimal.new(configuration.to_s)
33
+ when :less_than
34
+ return false unless value < BigDecimal.new(configuration.to_s)
35
+ when :less_than_or_equal_to
36
+ return false unless value <= BigDecimal.new(configuration.to_s)
37
+ when :equal_to
38
+ return false unless value == BigDecimal.new(configuration.to_s)
39
+ end
40
+ end
41
+
42
+ return true
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ require "anodator/validator/base"
2
+
3
+ module Anodator
4
+ module Validator
5
+ # presence validator
6
+ #
7
+ # This is the Validator to validate whether the value is present.
8
+ class PresenceValidator < Base
9
+ def validate
10
+ return !target_value.split(//).size.zero?
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # load validators
2
+ require "anodator/validator/base"
3
+ require "anodator/validator/blank_validator"
4
+ require "anodator/validator/complex_validator"
5
+ require "anodator/validator/format_validator"
6
+ require "anodator/validator/inclusion_validator"
7
+ require "anodator/validator/length_validator"
8
+ require "anodator/validator/numeric_validator"
9
+ require "anodator/validator/presence_validator"
10
+ require "anodator/validator/date_validator"
data/lib/anodator.rb ADDED
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ require "anodator/checker"
@@ -0,0 +1,101 @@
1
+ require "spec_helper"
2
+
3
+ # Anodator::CheckResult
4
+ require "anodator/check_result"
5
+
6
+ include Anodator
7
+
8
+ describe CheckResult, ".new" do
9
+ context "with no parameters" do
10
+ it "should raise error ArgumentError" do
11
+ lambda {
12
+ CheckResult.new
13
+ }.should raise_error ArgumentError
14
+ end
15
+ end
16
+
17
+ context "with only target_numbers" do
18
+ it "should raise error ArgumentError" do
19
+ lambda {
20
+ CheckResult.new(["1", "2"])
21
+ }.should raise_error ArgumentError
22
+ end
23
+ end
24
+
25
+ context "with target_numbers and message" do
26
+ before(:each) do
27
+ @new_proc = lambda {
28
+ CheckResult.new(["1", "2"], "An error occured for 1 and 2 values.")
29
+ }
30
+ end
31
+
32
+ it "should raise ArgumentError" do
33
+ @new_proc.should raise_error ArgumentError
34
+ end
35
+ end
36
+ context "with target_numbers, message and level" do
37
+ before(:each) do
38
+ @new_proc = lambda {
39
+ CheckResult.new(["1", "2"], "An error occured for 1 and 2 values.", Rule::LEVEL_ERROR)
40
+ }
41
+ end
42
+
43
+ it "should not raise error" do
44
+ @new_proc.should_not raise_error
45
+ end
46
+
47
+ context "after generated" do
48
+ before(:each) do
49
+ @check_result = @new_proc.call
50
+ end
51
+
52
+ it "#target_numbers should be set" do
53
+ @check_result.target_numbers.should == ["1", "2"]
54
+ end
55
+
56
+ it "#message should be set" do
57
+ @check_result.message.should == "An error occured for 1 and 2 values."
58
+ end
59
+
60
+ it "#level should be set" do
61
+ @check_result.level.should == Rule::LEVEL_ERROR
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ describe CheckResult, "#error?" do
68
+ context "when level is error" do
69
+ before(:each) do
70
+ @check_result = CheckResult.new("1", "message", Rule::LEVEL_ERROR)
71
+ end
72
+
73
+ it { @check_result.should be_error }
74
+ end
75
+
76
+ context "when level is warning" do
77
+ before(:each) do
78
+ @check_result = CheckResult.new("1", "message", Rule::LEVEL_WARNING)
79
+ end
80
+
81
+ it { @check_result.should_not be_error }
82
+ end
83
+ end
84
+
85
+ describe CheckResult, "#warning?" do
86
+ context "when level is error" do
87
+ before(:each) do
88
+ @check_result = CheckResult.new("1", "message", Rule::LEVEL_ERROR)
89
+ end
90
+
91
+ it { @check_result.should_not be_warning }
92
+ end
93
+
94
+ context "when level is warning" do
95
+ before(:each) do
96
+ @check_result = CheckResult.new("1", "message", Rule::LEVEL_WARNING)
97
+ end
98
+
99
+ it { @check_result.should be_warning }
100
+ end
101
+ end