paranoid_starlight 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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in paranoid_starlight.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Ivan Stana
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,61 @@
1
+ # ParanoidStarlight
2
+
3
+ This piece of gem contains some custom validators and converters for ActiveModel.
4
+
5
+ It have validations for email and name (European style).
6
+ And validation and converter (to international format) of telephone number. (CZ/SK format)
7
+
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'paranoid_starlight'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install paranoid_starlight
22
+
23
+ ## Usage
24
+
25
+ class MyModel
26
+ include ActiveModel::Validations
27
+ include ParanoidStarlight::Validations
28
+
29
+ attr_accessor :email
30
+ validates_email_format_of :email
31
+ end
32
+
33
+ model = MyModel.new
34
+ model.email = 'example@example.org'
35
+ model.valid?
36
+
37
+ or put this into /config/initializers/paranoid.rb
38
+
39
+ ActiveRecord::Base.send(:include, ParanoidStarlight::Validations)
40
+ ActiveRecord::Base.send(:include, ParanoidStarlight::Converters)
41
+
42
+ Now you have them available globally for models
43
+
44
+ class Person < ActiveRecord::Base
45
+ attr_accessible :name, :telephone, :email
46
+ validates_email_format_of :email
47
+ validates_name_format_of :name
48
+ validates_telephone_format_of :telephone
49
+ # or validates :email, :email => true
50
+
51
+ before_save :convert_telephone_number(:telephone)
52
+ end
53
+
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
60
+ 4. Push to the branch (`git push origin my-new-feature`)
61
+ 5. Create new Pull Request
@@ -0,0 +1,3 @@
1
+ module ParanoidStarlight
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,136 @@
1
+ # -*- coding: UTF-8 -*-
2
+
3
+ require "paranoid_starlight/version"
4
+ require 'active_model'
5
+ require 'twitter_cldr'
6
+ require 'fast_gettext'
7
+
8
+ module ParanoidStarlight
9
+
10
+ module Validators
11
+ class EmailValidator < ::ActiveModel::EachValidator
12
+ def validate_each(record, attribute, value)
13
+ # username in email may have @ in string
14
+ # username should be case sensitive, domain is not
15
+ unless value =~ %r{\A([^\s]+)@((?:[-a-zA-Z0-9]+\.)+[a-zA-Z]{2,})\z}
16
+ record.errors[attribute] << (options[:message] || 'is not an email')
17
+ end
18
+ end
19
+ end
20
+
21
+ class NameValidator < ::ActiveModel::EachValidator
22
+ def validate_each(record, attribute, value)
23
+ fullname = '\p{Letter}+(-\p{Letter}+)*'
24
+ surname = fullname
25
+ short = '\p{Letter}\.'
26
+ unless value =~ /\A(?:#{fullname} ((#{fullname}|#{short}) )*#{surname})\z/
27
+ record.errors[attribute] << (options[:message] || 'is not a name')
28
+ end
29
+ end
30
+ end
31
+
32
+ class TelephoneValidator < ::ActiveModel::EachValidator
33
+ def validate_each(record, attribute, value)
34
+ # SK/CZ format
35
+ valid = ::ParanoidStarlight::Converters.convert_telephone(value) rescue nil
36
+ unless valid
37
+ record.errors[attribute] << (options[:message] || 'is not a telephone number')
38
+ end
39
+ end
40
+ end
41
+ end # end validators
42
+
43
+ module Validations
44
+ def self.included(base)
45
+ base.send(:extend, self)
46
+ end
47
+
48
+ def validates_email_format_of(*attr_names)
49
+ # _merge_attributes extracts options and flatten attrs
50
+ # :attributes => {attr_names} is lightweight option
51
+ validates_with ::ParanoidStarlight::Validators::EmailValidator, _merge_attributes(attr_names)
52
+ end
53
+
54
+ def validates_name_format_of(*attr_names)
55
+ validates_with ::ParanoidStarlight::Validators::NameValidator, _merge_attributes(attr_names)
56
+ end
57
+
58
+ def validates_telephone_number_of(*attr_names)
59
+ validates_with ::ParanoidStarlight::Validators::TelephoneValidator, _merge_attributes(attr_names)
60
+ end
61
+ end # end validations
62
+
63
+
64
+ module Converters
65
+ def self.convert_telephone(num, prefixcc = 421)
66
+ telephone = num.to_s
67
+ prefixcc = prefixcc.to_s
68
+
69
+ # convert logic
70
+ # possible formats, with or without spaces
71
+
72
+ # mobile (CZ/SK)
73
+ # CZ/SK have always 9 numbers
74
+ # (1) +421 949 123 456
75
+ # (2) 00421 949 123 456
76
+ # (3) 0949 123 456 (10 with leading zero, only SK)
77
+ # (4) 949 123 456
78
+
79
+ # landline always 9 numbers
80
+ # other regions - 04x
81
+ # (3) 045 / 6893121
82
+ # bratislava - 02
83
+ # (3) 02 / 44250320
84
+ # (1) 421-2-44250320
85
+ # (1) +421 (2) 44250320
86
+ # (x) ()44 250 320 (no chance to guess NDC (geographic prefix here))
87
+ # and other formats from above
88
+
89
+
90
+ # output is integer
91
+ # 421949123456
92
+
93
+ # remove all non-number characters
94
+ telephone.gsub!(/\D/, '')
95
+
96
+ cc = '420|421'
97
+
98
+ # + is stripped
99
+ if match = /\A((?:#{cc})\d{9})\z/.match(telephone)
100
+ return match[1]
101
+ elsif match = /\A00((?:#{cc})\d{9})\z/.match(telephone)
102
+ return match[1]
103
+ elsif match = /\A0(\d{9})\z/.match(telephone)
104
+ return prefixcc + match[1]
105
+ # number cannot begin with 0, when has 9 numbers
106
+ elsif match = /\A([1-9]\d{8})\z/.match(telephone)
107
+ return prefixcc + match[1]
108
+
109
+ else
110
+ raise("Number is invalid")
111
+ end
112
+ end
113
+
114
+ def convert_telephone_number(inattr, outattr = '')
115
+ inattr = inattr.to_s
116
+ outattr = outattr.to_s
117
+
118
+ if self.respond_to? inattr.to_sym
119
+ outattr = inattr if outattr == ''
120
+ raise("Attribute #{outattr} does not exist.") unless self.respond_to? outattr.to_sym
121
+ setter = "#{outattr}=".to_sym
122
+
123
+ telephone = self.send(inattr.to_sym)
124
+
125
+ num = ::ParanoidStarlight::Converters.convert_telephone(telephone,
126
+ TwitterCldr::Shared::PhoneCodes.code_for_territory(FastGettext.locale.to_sym)
127
+ ) rescue nil
128
+
129
+ self.send(setter, num) unless num.nil?
130
+ else
131
+ raise("Attribute #{inattr} does not exist.")
132
+ end
133
+ end
134
+
135
+ end # end converters
136
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'paranoid_starlight/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "paranoid_starlight"
8
+ gem.version = ParanoidStarlight::VERSION
9
+ gem.author = 'Ivan Stana'
10
+ gem.email = 'stiipa@centrum.sk'
11
+ gem.summary = "Pack of custom validations and converters for ActiveModel"
12
+ gem.description = <<-EOF
13
+ Validators for name and email. Converter and validator for
14
+ telephone number (CZ/SK format). ActiveModel. Specs included.
15
+ EOF
16
+
17
+ gem.homepage = "http://github.com/istana/paranoid_starlight"
18
+
19
+ gem.files = `git ls-files`.split($/)
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.require_paths = ["lib"]
22
+
23
+ gem.add_dependency("activemodel", ["~> 3.2"])
24
+ gem.add_dependency("twitter_cldr", ["~> 2.0"])
25
+ gem.add_dependency("fast_gettext", ["~> 0.6"])
26
+
27
+ gem.add_development_dependency("rspec")
28
+ gem.required_ruby_version = '>= 1.9.2'
29
+ end
@@ -0,0 +1,240 @@
1
+ require_relative '../lib/paranoid_starlight'
2
+ require 'rspec'
3
+
4
+ #ActiveRecord::Base.send(:include, ParanoidStarlight::Validators)
5
+ #ActiveRecord::Base.send(:include, ParanoidStarlight::Converters)
6
+
7
+ class Fangirl
8
+ include ::ParanoidStarlight::Converters
9
+ attr_accessor :telephone_from_form, :telephone
10
+ end
11
+
12
+ describe ParanoidStarlight::Converters do
13
+ before :all do
14
+ @p = ParanoidStarlight::Converters
15
+ end
16
+
17
+ describe 'convert_telephone' do
18
+
19
+ it 'accepts all objects, which have to_s' do
20
+ ['421123456789',
21
+ 421123456789,
22
+ :"421123456789"].each do |num|
23
+ @p.convert_telephone(num).should == '421123456789'
24
+ end
25
+ end
26
+
27
+ it 'removes non-numeric characters' do
28
+ @p.convert_telephone(' +421 123 / 456789A').should == '421123456789'
29
+ end
30
+
31
+ it 'tests (un)polished valid formats' do
32
+ ['+421 123 456 789',
33
+ '00421 123 456 789',
34
+ '123 456 789',
35
+ '0123 456 789'].each { |num|
36
+ @p.convert_telephone(num).should == '421123456789'
37
+ }
38
+ @p.convert_telephone('043/5867890').should == '421435867890'
39
+ end
40
+
41
+ it 'tests some of invalid formats' do
42
+ ['043/586789',
43
+ '123',
44
+ '4211234567890'
45
+ ].each { |num|
46
+ expect {@p.convert_telephone(num)}.to raise_error('Number is invalid')
47
+ }
48
+ end
49
+
50
+ it 'tests with custom country code prefix' do
51
+ @p.convert_telephone('+421 123 456 789', 410).should == '421123456789'
52
+ @p.convert_telephone('123 456 789', 410).should == '410123456789'
53
+ @p.convert_telephone('0123 456 789', 410).should == '410123456789'
54
+ end
55
+
56
+ end
57
+
58
+ describe 'convert_telephone_number' do
59
+ before :each do
60
+ FastGettext.locale = 'sk'
61
+ @test = Fangirl.new
62
+ @test.telephone_from_form = '+421 123 456 789'
63
+ end
64
+
65
+ context 'with two parameters - input and output attribute' do
66
+ it 'should store result in second parameter' do
67
+ @test.convert_telephone_number(:telephone_from_form, :telephone)
68
+ @test.telephone.should == '421123456789'
69
+ end
70
+ end
71
+
72
+ context 'with only one parameter' do
73
+ it 'should convert telephone number and overwrite original' do
74
+ @test.convert_telephone_number(:telephone_from_form)
75
+ @test.telephone_from_form.should == '421123456789'
76
+ end
77
+ end
78
+
79
+ end
80
+ end
81
+
82
+ describe 'ParanoidStarlight::Validations' do
83
+ before(:each) do
84
+ @validators = ParanoidStarlight::Validators
85
+
86
+ @mock = mock('model')
87
+ @mock.stub("errors").and_return([])
88
+ @mock.errors.stub('[]').and_return({})
89
+ @mock.errors[].stub('<<')
90
+ end
91
+
92
+ describe 'EmailValidator' do
93
+ before :each do
94
+ @email = @validators::EmailValidator.new({:attributes => {}})
95
+ end
96
+
97
+ it "should validate valid email address" do
98
+ @mock.should_not_receive('errors')
99
+ @email.validate_each(@mock, "email", "example@example.org")
100
+ @email.validate_each(@mock, "email", "example@@example.org")
101
+ @email.validate_each(@mock, "email", "l0~gin@sub.examp-le.org")
102
+ end
103
+
104
+ it "should validate invalid email address" do
105
+ @mock.errors[].should_receive('<<')
106
+ @email.validate_each(@mock, "email", "notvalid")
107
+ @email.validate_each(@mock, "email", "x@exa$mple.org")
108
+ end
109
+ end
110
+
111
+ describe 'NameValidator' do
112
+ before :each do
113
+ @name = @validators::NameValidator.new({:attributes => {}})
114
+ end
115
+
116
+ it "should validate valid name" do
117
+ @mock.should_not_receive('errors')
118
+ [
119
+ 'Ivan Stana', 'Ivan R. Stana', 'Ivan Ronon Stana',
120
+ 'Jean Claude Van Damme', 'Jean-Pierre Cassel',
121
+ 'Tatyana Sukhotina-Tolstaya',
122
+ 'John R. R. Tolkien'
123
+ ].each {
124
+ |name| @name.validate_each(@mock, "name", name)
125
+ }
126
+ end
127
+
128
+ it "should validate invalid name" do
129
+ @mock.errors[].should_receive('<<')
130
+ [
131
+ 'J. R. R. Tolkien', 'J.R.R. Tolkien', 'Tolkien'
132
+ ].each {
133
+ |name| @name.validate_each(@mock, "name", name)
134
+ }
135
+ end
136
+ end
137
+
138
+ describe 'TelephoneValidator' do
139
+ before :each do
140
+ @telephone = @validators::TelephoneValidator.new({:attributes => {}})
141
+ end
142
+
143
+ it "should validate valid telephone" do
144
+ @mock.should_not_receive('errors')
145
+ @telephone.validate_each(@mock, "telephone", '+421123456789')
146
+ end
147
+
148
+ it "should validate invalid telephone" do
149
+ @mock.errors[].should_receive('<<')
150
+ @telephone.validate_each(@mock, "telephone", '123')
151
+ end
152
+ end
153
+
154
+ describe 'model Validators of' do
155
+ class TestEmail
156
+ include ActiveModel::Validations
157
+ include ParanoidStarlight::Validations
158
+ attr_accessor :email_field
159
+ validates_email_format_of :email_field
160
+ end
161
+
162
+ class TestName
163
+ include ActiveModel::Validations
164
+ include ParanoidStarlight::Validations
165
+ attr_accessor :name_field
166
+ validates_name_format_of :name_field
167
+ end
168
+
169
+ class TestName
170
+ include ActiveModel::Validations
171
+ include ParanoidStarlight::Validations
172
+ attr_accessor :name_field
173
+ validates_name_format_of :name_field
174
+ end
175
+
176
+ class TestTelephone
177
+ include ActiveModel::Validations
178
+ include ParanoidStarlight::Validations
179
+ attr_accessor :telephone
180
+ validates_telephone_number_of :telephone
181
+ end
182
+ # I don't test multiple attributes as argument
183
+ # it works, because it is copied from rails
184
+
185
+
186
+ describe 'Email' do
187
+ subject { TestEmail.new() }
188
+
189
+ before { subject.email_field = email_value }
190
+
191
+ context 'is valid' do
192
+ let(:email_value) {'example@my.example.org'}
193
+ it {should be_valid }
194
+ end
195
+
196
+ context 'is invalid' do
197
+ let(:email_value) {'example'}
198
+ it { should be_invalid }
199
+ end
200
+ end
201
+
202
+ describe 'Name' do
203
+ subject { TestName.new() }
204
+
205
+ before do
206
+ subject.name_field = name
207
+ end
208
+
209
+ context 'is valid' do
210
+ let(:name) {'Geralt of Rivia'}
211
+ it { should be_valid }
212
+ end
213
+
214
+ context 'is invalid' do
215
+ let(:name) {'Shakespeare'}
216
+ it { should be_invalid }
217
+ end
218
+ end
219
+
220
+ describe 'Telephone' do
221
+ subject { TestTelephone.new() }
222
+
223
+ before do
224
+ subject.telephone = telephone
225
+ end
226
+
227
+ context 'is valid' do
228
+ let(:telephone) {'+421123456789'}
229
+ it { should be_valid }
230
+ end
231
+
232
+ context 'is invalid' do
233
+ let(:telephone) {'1111'}
234
+ it { should be_invalid }
235
+ end
236
+ end
237
+
238
+ end
239
+
240
+ end # end validations
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paranoid_starlight
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ivan Stana
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activemodel
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.2'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ - !ruby/object:Gem::Dependency
31
+ name: twitter_cldr
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: fast_gettext
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '0.6'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.6'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: ! " Validators for name and email. Converter and validator for\n telephone
79
+ number (CZ/SK format). ActiveModel. Specs included.\n"
80
+ email: stiipa@centrum.sk
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - lib/paranoid_starlight.rb
90
+ - lib/paranoid_starlight/version.rb
91
+ - paranoid_starlight.gemspec
92
+ - specs/paranoid_starlight_spec.rb
93
+ homepage: http://github.com/istana/paranoid_starlight
94
+ licenses: []
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: 1.9.2
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 1.8.24
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: Pack of custom validations and converters for ActiveModel
117
+ test_files: []