anodator 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.
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