tsubaki 0.1.1 → 0.2.0

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: 6670c698e5b096b76addb7bbd8ced4ea7c615543
4
- data.tar.gz: 4e011f826744fc43867213bd393a2f7684d1b2f1
3
+ metadata.gz: 610420f558197c1c9c9caea8f6dc1ae4f6bc507b
4
+ data.tar.gz: 482b6a9fecb8cc423fdaa606242b26b5bfa53889
5
5
  SHA512:
6
- metadata.gz: af07b276c392ad68c61b9ea826a8b383bbb8295c44c1a6381b4dbdc80499d19008c49cc0ab76b2bda9629f078464fdac06554f8fe301332ac820e7ec1e378a28
7
- data.tar.gz: bcb7c76f100c94da586d05c07f74fc29161527fdb6aafa88d9a1c99e16f13c8e1c4ecf30321e9c9f878397afd34c87effa0f2b8863e3f00c5754b31b840514ed
6
+ metadata.gz: 9bc874bf0b0e19329bf29fc03a61e65e808847bf827c96a5d72b1cf594147eefc8e68206b00d2bf257ac00531d9bd7d5f1dd1b75f9eea917bad0b57da4ca1532
7
+ data.tar.gz: 5beea1081c4357a8cb759ab6788079e9433104e79129d769466809ed49140413885b75b9d7c50f599ab40be9fdf64779ec9e11535a5654063137503ba36c63c0
data/.rubocop.yml CHANGED
@@ -13,4 +13,7 @@ Style/DoubleNegation:
13
13
  Enabled: false
14
14
 
15
15
  Metrics/AbcSize:
16
- Max: 18
16
+ Max: 18
17
+
18
+ Metrics/ClassLength:
19
+ Max: 200
data/README.md CHANGED
@@ -1,13 +1,10 @@
1
1
  # Tsubaki
2
2
 
3
- [![Circle CI](https://circleci.com/gh/kakipo/tsubaki/tree/master.svg?style=svg)](https://circleci.com/gh/kakipo/tsubaki/tree/master)
3
+ [![Circle CI](https://circleci.com/gh/kufu/tsubaki/tree/master.svg?style=svg)](https://circleci.com/gh/kufu/tsubaki/tree/master)
4
4
 
5
- Each resident in Japan will be notified of his or her own Individual Number (a.k.a. "My Number") beginning in October 2015.
5
+ Each resident in Japan will be notified of his or her own Individual Number (a.k.a. "My Number") beginning in October 2015, and each company will be given its own Corporate Number likewise.
6
6
 
7
- A My Number consists of 12 digits & the last digit is used as a check digit.
8
- This gem provides My Number validator which inspects the format and (optionally) the check digit.
9
-
10
- (We plan to implement other social security related code validators such as a basic pension number validator later.)
7
+ This gem provides both My Number and Corporate Number validators which inspect the format and (optionally) the check digit.
11
8
 
12
9
  ## Installation
13
10
 
@@ -27,38 +24,86 @@ Or install it yourself as:
27
24
 
28
25
  ## Usage
29
26
 
30
- Add the following to your model:
27
+
28
+ ### My Number
29
+
30
+ A My Number consists of 12 digits & the last digit is used as a check digit.
31
+
32
+ To validate the format of an attribute, add the following to your model:
31
33
 
32
34
  ```ruby
33
- validates :my_number, my_number: true
35
+ # Verifies the format and its check digit with `strict` option:
36
+ validates :digits, my_number: { strict: true }, allow_nil: true
37
+
38
+ # Without strict option, it verifies only the length of the digits:
39
+ validates :digits, my_number: true
40
+
41
+ # Or if a My Number contains any dividers, specify it:
42
+ validates :digits, my_number: { strict: true, divider: '-' } # => 4652-8126-6333 should be valid
34
43
  ```
35
44
 
36
- ## Verify the check digit
45
+ ### Corporate Number
46
+
47
+ A Corporate Number consists of 13 digits & the first digit is used as a check digit.
37
48
 
38
- In order to have stricter validation which verifies the check digit, enable strict mode.
49
+ To validate the format of an attribute, add the following to your model:
39
50
 
40
51
  ```ruby
41
- validates :my_number, my_number: { strict: true }
52
+ # Verifies the format and its check digit with `strict` option:
53
+ validates :digits, corporate_number: { strict: true }, allow_nil: true
54
+
55
+ # Without strict option, it verifies only the length of the digits:
56
+ validates :digits, corporate_number: true
57
+
58
+ # Or if a Corporate Number contains any dividers, specify it:
59
+ validates :digits, corporate_number: { strict: true, divider: '-' } # => 5-8356-7825-6246 should be valid
42
60
  ```
43
61
 
44
- See: [行政手続における特定の個人を識別するための番号の利用等に関する法律の規定による通知カード及び個人番号カード並びに情報提供ネットワークシステムによる特定個人情報の提供等に関する省令](http://law.e-gov.go.jp/announce/H26F11001000085.html)
45
62
 
46
- ## Divider
47
63
 
48
- If a My Number contains any dividers, specify it.
64
+ ## Goodies
65
+
66
+ ### Rspec matchers
67
+
68
+ To ensure appropriate validations are specified, Tsubaki includes rspec matchers.
49
69
 
50
70
  ```ruby
51
- # 1111-2222-3333-4444 should be valid
52
- validates :my_number, my_number: { divider: '-' }
71
+ # In spec_helper.rb, you'll need to require the matchers:
72
+ require 'tsubaki/matchers'
73
+
74
+ # And include the module:
75
+ RSpec.configure do |config|
76
+ config.include Tsubaki::Shoulda::Matchers
77
+ end
53
78
  ```
54
79
 
55
- ## Goodies
80
+ ```ruby
81
+ describe User do
82
+ # For My Number validation
83
+ it { should validate_my_number_of(:digits) }
84
+
85
+ # To ensure options:
86
+ it { should validate_validate_my_number_of(:digits).strict.with_divider('-').allow_nil }
87
+ end
88
+
89
+ describe Company do
90
+ # For Corporate Number validation
91
+ it { should validate_corporate_number_of(:digits) }
92
+
93
+ # To ensure options:
94
+ it { should validate_validate_corporate_number_of(:digits).strict.with_divider('-') }
95
+ end
96
+ ```
97
+
98
+
99
+ ### Random number generators
56
100
 
57
- You can obtain a random yet having right check digit My Number.
101
+ You can obtain a random yet having right check digit numbers.
58
102
  This is useful when creating dummy records.
59
103
 
60
104
  ```ruby
61
105
  Tsubaki::MyNumber.rand # => 765895492872
106
+ Tsubaki::CorporateNumber.rand # => 5868731863533
62
107
  ```
63
108
 
64
109
  ## Development
@@ -69,7 +114,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
69
114
 
70
115
  ## Contributing
71
116
 
72
- Bug reports and pull requests are welcome on GitHub at https://github.com/kakipo/tsubaki.
117
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kufu/tsubaki.
73
118
 
74
119
 
75
120
  ## License
@@ -0,0 +1,46 @@
1
+ module Tsubaki
2
+ class CorporateNumber
3
+ def self.rand
4
+ digits = 12.times.map { Kernel.rand(10) }.join
5
+ check_digit = calc_check_digit(digits)
6
+ "#{check_digit}#{digits}"
7
+ end
8
+
9
+ def self.calc_check_digit(digits)
10
+ fail 'must be a 12 digit number' unless digits =~ /\A\d{12}\z/
11
+
12
+ arr = digits.chars.map(&:to_i).reverse!
13
+ rem = (1..12).inject(0) do |sum, n|
14
+ pn = arr[n - 1]
15
+ qn = n.odd? ? 1 : 2
16
+ sum + pn * qn
17
+ end % 9
18
+
19
+ 9 - rem
20
+ end
21
+
22
+ def initialize(digits, options = {})
23
+ @digits = digits.to_s.freeze
24
+ @options = options
25
+ end
26
+
27
+ def valid?
28
+ @options[:strict] ? valid_check_digit? : valid_pattern?
29
+ end
30
+
31
+ def valid_pattern?
32
+ !!(plain_digits =~ /\A\d{13}\z/)
33
+ end
34
+
35
+ def valid_check_digit?
36
+ return false unless valid_pattern?
37
+ plain_digits[0].to_i == self.class.calc_check_digit(plain_digits[1, 12]).to_i
38
+ end
39
+
40
+ private
41
+
42
+ def plain_digits
43
+ @plain_digits ||= @digits.split(@options[:divider]).join('')
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ require 'active_model'
2
+ require 'active_model/validator'
3
+
4
+ module Tsubaki
5
+ class CorporateNumberValidator < ActiveModel::EachValidator
6
+ def validate_each(record, attribute, value)
7
+ return if Tsubaki::CorporateNumber.new(value, options).valid?
8
+ record.errors.add(attribute, options[:message] || :invalid)
9
+ end
10
+ end
11
+ end
12
+
13
+ ActiveModel::Validations::CorporateNumberValidator = Tsubaki::CorporateNumberValidator
@@ -0,0 +1,157 @@
1
+ module Tsubaki
2
+ module Shoulda
3
+ module Matchers
4
+ # Ensures that the given instance or class validates the format of
5
+ # the corporate number as specified.
6
+ #
7
+ # Example:
8
+ # describe Corporation do
9
+ # it { should validate_corporate_number_of(:digits)
10
+ # it { should validate_corporate_number_of(:digits).strict.with_divider('-') }
11
+ # end
12
+ def validate_corporate_number_of(attribute_name)
13
+ ValidateCorporateNumberOfMatcher.new(attribute_name)
14
+ end
15
+
16
+ class ValidateCorporateNumberOfMatcher
17
+ def initialize(attribute_name)
18
+ @attribute_name = attribute_name
19
+ @options = {}
20
+ @options[:strict] = nil
21
+ @options[:divider] = nil
22
+ @options[:allow_nil] = nil
23
+ @failure_messages = []
24
+ self
25
+ end
26
+
27
+ def matches?(subject)
28
+ @subject = subject
29
+ @subject = @subject.new if @subject.class == Class
30
+ (error_when_not_valid + no_error_when_valid).all?
31
+ end
32
+
33
+ def failure_message
34
+ @failure_messages.join("\n")
35
+ end
36
+
37
+ def description
38
+ result = 'ensure corporate number format'
39
+ result << " for #{@attribute_name}"
40
+ result << ' with strict mode' if @options[:strict].present?
41
+ result << " with divider '#{@options[:divider]}'" if @options[:divider].present?
42
+ result << ' and allow nil' if @options[:allow_nil].present?
43
+ result
44
+ end
45
+
46
+ def strict(strict = true)
47
+ @options[:strict] = strict
48
+ self
49
+ end
50
+
51
+ def with_divider(divider)
52
+ @options[:divider] = divider
53
+ self
54
+ end
55
+
56
+ def allow_nil(allow_nil = true)
57
+ @options[:allow_nil] = allow_nil
58
+ self
59
+ end
60
+
61
+ protected
62
+
63
+ def error_when_not_valid
64
+ [error_test_allow_nil, error_test_strict, error_test_divider, error_test]
65
+ end
66
+
67
+ def no_error_when_valid
68
+ [no_error_test_allow_nil, no_error_test_strict, no_error_test_divider, no_error_test]
69
+ end
70
+
71
+ private
72
+
73
+ def valid_attribute_with?(value)
74
+ dup_subject = @subject.dup
75
+ dup_subject.send("#{@attribute_name}=", value)
76
+ dup_subject.valid?
77
+ dup_subject.errors[@attribute_name].blank?
78
+ end
79
+
80
+ def error_test_allow_nil
81
+ true
82
+ end
83
+
84
+ def error_test_strict
85
+ return true if @options[:strict].nil?
86
+
87
+ if valid_attribute_with?('1111111111111')
88
+ @failure_messages << 'strict mode is not be specified'
89
+ false
90
+ else
91
+ true
92
+ end
93
+ end
94
+
95
+ def error_test_divider
96
+ return true if @options[:divider].nil?
97
+
98
+ dummy_divider = @options[:divider].succ
99
+ invalid_corporate_number = "7#{dummy_divider}1234#{dummy_divider}5678#{dummy_divider}9012"
100
+
101
+ if valid_attribute_with?(invalid_corporate_number)
102
+ @failure_messages << "divider is not be specified or is not '#{@options[:divider]}'"
103
+ false
104
+ else
105
+ true
106
+ end
107
+ end
108
+
109
+ def error_test
110
+ if valid_attribute_with?('xaaaabbbbcccc')
111
+ @failure_messages << 'corporate number validation is not specified'
112
+ false
113
+ else
114
+ true
115
+ end
116
+ end
117
+
118
+ def no_error_test_allow_nil
119
+ return true if @options[:allow_nil].nil?
120
+
121
+ if !valid_attribute_with?(nil)
122
+ @failure_messages << 'allow_nil is not be specified'
123
+ false
124
+ else
125
+ true
126
+ end
127
+ end
128
+
129
+ def no_error_test_strict
130
+ true
131
+ end
132
+
133
+ def no_error_test_divider
134
+ return true if @options[:divider].nil?
135
+
136
+ valid_corporate_number = "7#{@options[:divider]}1234#{@options[:divider]}5678#{@options[:divider]}9012"
137
+
138
+ if !valid_attribute_with?(valid_corporate_number)
139
+ @failure_messages << "divider is not be specified or is not '#{@options[:divider]}'"
140
+ false
141
+ else
142
+ true
143
+ end
144
+ end
145
+
146
+ def no_error_test
147
+ if !valid_attribute_with?('7123456789012')
148
+ @failure_messages << 'corporate number validation is not specified'
149
+ false
150
+ else
151
+ true
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,157 @@
1
+ module Tsubaki
2
+ module Shoulda
3
+ module Matchers
4
+ # Ensures that the given instance or class validates the format of
5
+ # the my number as specified.
6
+ #
7
+ # Example:
8
+ # describe User do
9
+ # it { should validate_my_number_of(:digits)
10
+ # it { should validate_my_number_of(:digits).strict.with_divider('-') }
11
+ # end
12
+ def validate_my_number_of(attribute_name)
13
+ ValidateMyNumberOfMatcher.new(attribute_name)
14
+ end
15
+
16
+ class ValidateMyNumberOfMatcher
17
+ def initialize(attribute_name)
18
+ @attribute_name = attribute_name
19
+ @options = {}
20
+ @options[:strict] = nil
21
+ @options[:divider] = nil
22
+ @options[:allow_nil] = nil
23
+ @failure_messages = []
24
+ self
25
+ end
26
+
27
+ def matches?(subject)
28
+ @subject = subject
29
+ @subject = @subject.new if @subject.class == Class
30
+ (error_when_not_valid + no_error_when_valid).all?
31
+ end
32
+
33
+ def failure_message
34
+ @failure_messages.join("\n")
35
+ end
36
+
37
+ def description
38
+ result = 'ensure my number format'
39
+ result << " for #{@attribute_name}"
40
+ result << ' with strict mode' if @options[:strict].present?
41
+ result << " with divider '#{@options[:divider]}'" if @options[:divider].present?
42
+ result << ' and allow nil' if @options[:allow_nil].present?
43
+ result
44
+ end
45
+
46
+ def strict(strict = true)
47
+ @options[:strict] = strict
48
+ self
49
+ end
50
+
51
+ def with_divider(divider)
52
+ @options[:divider] = divider
53
+ self
54
+ end
55
+
56
+ def allow_nil(allow_nil = true)
57
+ @options[:allow_nil] = allow_nil
58
+ self
59
+ end
60
+
61
+ protected
62
+
63
+ def error_when_not_valid
64
+ [error_test_allow_nil, error_test_strict, error_test_divider, error_test]
65
+ end
66
+
67
+ def no_error_when_valid
68
+ [no_error_test_allow_nil, no_error_test_strict, no_error_test_divider, no_error_test]
69
+ end
70
+
71
+ private
72
+
73
+ def valid_attribute_with?(value)
74
+ dup_subject = @subject.dup
75
+ dup_subject.send("#{@attribute_name}=", value)
76
+ dup_subject.valid?
77
+ dup_subject.errors[@attribute_name].blank?
78
+ end
79
+
80
+ def error_test_allow_nil
81
+ true
82
+ end
83
+
84
+ def error_test_strict
85
+ return true if @options[:strict].nil?
86
+
87
+ if valid_attribute_with?('111111111111')
88
+ @failure_messages << 'strict mode is not be specified'
89
+ false
90
+ else
91
+ true
92
+ end
93
+ end
94
+
95
+ def error_test_divider
96
+ return true if @options[:divider].nil?
97
+
98
+ dummy_divider = @options[:divider].succ
99
+ invalid_my_number = "9656#{dummy_divider}7219#{dummy_divider}7231"
100
+
101
+ if valid_attribute_with?(invalid_my_number)
102
+ @failure_messages << "divider is not be specified or is not '#{@options[:divider]}'"
103
+ false
104
+ else
105
+ true
106
+ end
107
+ end
108
+
109
+ def error_test
110
+ if valid_attribute_with?('aaaabbbbcccc')
111
+ @failure_messages << 'my number validation is not specified'
112
+ false
113
+ else
114
+ true
115
+ end
116
+ end
117
+
118
+ def no_error_test_allow_nil
119
+ return true if @options[:allow_nil].nil?
120
+
121
+ if !valid_attribute_with?(nil)
122
+ @failure_messages << 'allow_nil is not be specified'
123
+ false
124
+ else
125
+ true
126
+ end
127
+ end
128
+
129
+ def no_error_test_strict
130
+ true
131
+ end
132
+
133
+ def no_error_test_divider
134
+ return true if @options[:divider].nil?
135
+
136
+ valid_my_number = "9656#{@options[:divider]}7219#{@options[:divider]}7231"
137
+
138
+ if !valid_attribute_with?(valid_my_number)
139
+ @failure_messages << "divider is not be specified or is not '#{@options[:divider]}'"
140
+ false
141
+ else
142
+ true
143
+ end
144
+ end
145
+
146
+ def no_error_test
147
+ if !valid_attribute_with?('965672197231')
148
+ @failure_messages << 'my number validation is not specified'
149
+ false
150
+ else
151
+ true
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,52 @@
1
+ require 'tsubaki/matchers/validate_my_number_of_matcher'
2
+ require 'tsubaki/matchers/validate_corporate_number_of_matcher'
3
+
4
+ module Tsubaki
5
+ module Shoulda
6
+ # Provides RSpec-compatible & Test::Unit-compatible matchers for testing Tsubaki modules.
7
+ #
8
+ # *RSpec*
9
+ #
10
+ # In spec_helper.rb, you'll need to require the matchers:
11
+ #
12
+ # require "tsubaki/matchers"
13
+ #
14
+ # And _include_ the module:
15
+ #
16
+ # RSpec.configure do |config|
17
+ # config.include Tsubaki::Shoulda::Matchers
18
+ # end
19
+ #
20
+ # Example:
21
+ # describe User do
22
+ # it { should validate_my_number_of(:digits) }
23
+ # it { should validate_validate_my_number_of(:digits).strict.with_divider('-') }
24
+ # end
25
+ #
26
+ #
27
+ # *TestUnit*
28
+ #
29
+ # In test_helper.rb, you'll need to require the matchers as well:
30
+ #
31
+ # require "tubaki/matchers"
32
+ #
33
+ # And _extend_ the module:
34
+ #
35
+ # class ActiveSupport::TestCase
36
+ # extend Tsubaki::Shoulda::Matchers
37
+ #
38
+ # #...other initializers...#
39
+ # end
40
+ #
41
+ # Example:
42
+ # require 'test_helper'
43
+ #
44
+ # class UserTest < ActiveSupport::TestCase
45
+ # should validate_validate_my_number_of(:digits)
46
+ # should validate_validate_my_number_of(:digits).strict.with_divider('-')
47
+ # end
48
+ #
49
+ module Matchers
50
+ end
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module Tsubaki
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/tsubaki.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  require 'tsubaki/version'
2
2
  require 'tsubaki/my_number'
3
3
  require 'tsubaki/my_number_validator'
4
+ require 'tsubaki/corporate_number'
5
+ require 'tsubaki/corporate_number_validator'
4
6
 
5
7
  module Tsubaki
6
- # Your code goes here...
7
8
  end
data/tsubaki.gemspec CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ['kakipo@gmail.com']
11
11
 
12
12
  spec.summary = 'Japanese soocial security code validators.'
13
- spec.description = 'A gem provides several social security code validators such as My Number validator, Basic Pension Number validator.'
14
- spec.homepage = 'https://github.com/kakipo/tsubaki'
13
+ spec.description = 'A gem provides My Number & Corporate Number validators'
14
+ spec.homepage = 'https://github.com/kufu/tsubaki'
15
15
  spec.license = 'MIT'
16
16
 
17
17
  # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tsubaki
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kakipo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-20 00:00:00.000000000 Z
11
+ date: 2015-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,8 +122,7 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
- description: A gem provides several social security code validators such as My Number
126
- validator, Basic Pension Number validator.
125
+ description: A gem provides My Number & Corporate Number validators
127
126
  email:
128
127
  - kakipo@gmail.com
129
128
  executables: []
@@ -144,11 +143,16 @@ files:
144
143
  - bin/setup
145
144
  - circle.yml
146
145
  - lib/tsubaki.rb
146
+ - lib/tsubaki/corporate_number.rb
147
+ - lib/tsubaki/corporate_number_validator.rb
148
+ - lib/tsubaki/matchers.rb
149
+ - lib/tsubaki/matchers/validate_corporate_number_of_matcher.rb
150
+ - lib/tsubaki/matchers/validate_my_number_of_matcher.rb
147
151
  - lib/tsubaki/my_number.rb
148
152
  - lib/tsubaki/my_number_validator.rb
149
153
  - lib/tsubaki/version.rb
150
154
  - tsubaki.gemspec
151
- homepage: https://github.com/kakipo/tsubaki
155
+ homepage: https://github.com/kufu/tsubaki
152
156
  licenses:
153
157
  - MIT
154
158
  metadata: