in_format 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.txt +20 -0
- data/README.md +125 -0
- data/Rakefile +31 -0
- data/lib/in_format.rb +7 -0
- data/lib/in_format/core.rb +42 -0
- data/lib/in_format/formatters.rb +2 -0
- data/lib/in_format/formatters/phone.rb +65 -0
- data/lib/in_format/formatters/ssn.rb +26 -0
- data/lib/in_format/railtie.rb +13 -0
- data/lib/in_format/version.rb +3 -0
- metadata +127 -0
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2012 Cyrus Farajpour
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# InFormat
|
|
2
|
+
|
|
3
|
+
Easily add custom getter and setter filters for attributes on ActiveRecord objects. These can be useful if you wish to scrub data before it hits your datastore and/or provide uniformity when reading.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
For Ruby 1.9.0 and greater. Tested with Rails 3.1+ using ActiveRecord. It should work with any ORM that provides a hash syntax for accessing attributes in Models (please let me know if you have success/failures with other ORMs).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Add the requirement to your Gemfile
|
|
12
|
+
|
|
13
|
+
`gem "in_format"`
|
|
14
|
+
|
|
15
|
+
That's it if using ActiveRecord. If using a different ORM you will need to `extend InFormat` on the models, add an initializer or shoehorn it in some other way.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Invoke `in_format`, `phone_format` or `ssn_format` in your Model for attributes you wish to process.
|
|
20
|
+
|
|
21
|
+
### in_format
|
|
22
|
+
|
|
23
|
+
The `in_format` method is the most general and accepts a getter and/or a setter.
|
|
24
|
+
|
|
25
|
+
Under the hood these create setters/getters and process the value through the supplied Proc/lambda and set/read the value using the hash syntax (`self[:attribute_name]`).
|
|
26
|
+
|
|
27
|
+
There is an `use_accessor` option which will override getter/setter methods matching the attribute. This can be useful if you want to combine `in_format` with `attr_accessor` or gems like [attr_encrypted](https://github.com/shuber/attr_encrypted) (just be sure that the overridden methods exist before using `in_format`).
|
|
28
|
+
|
|
29
|
+
You can access the original getter by passing `true` to the new one (assuming you supplied a getter).
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
class MyModel < ActiveRecord::Base
|
|
33
|
+
in_format :name, setter: lambda {|v| v.upcase }, getter: lambda {|v| "Mrs. #{v}"}
|
|
34
|
+
|
|
35
|
+
attr_accessor :some_attribute
|
|
36
|
+
in_format :some_attribute, use_accessor: true, setter: -> v { "#{v}s"}, getter: -> v { "3 {v}"}
|
|
37
|
+
end
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
<pre>
|
|
41
|
+
m = MyModel.new(name: "shirley")
|
|
42
|
+
m.name(true) #=> "SHIRLEY"
|
|
43
|
+
m.name #=> "Mrs. SHIRLEY"
|
|
44
|
+
|
|
45
|
+
m.some_attribute = "beer"
|
|
46
|
+
m.some_attribute(true) #=> "beers"
|
|
47
|
+
m.some_attribute #=> "3 beers"
|
|
48
|
+
</pre>
|
|
49
|
+
|
|
50
|
+
This example is contrived and a little dangerous, `MyModel.new(name: nil) #=> splode!`, but you can do a lot with getters/setters.
|
|
51
|
+
|
|
52
|
+
### phone_format
|
|
53
|
+
|
|
54
|
+
`phone_format` uses `in_format` with some pre-defined getters and setters.
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
class MyModel < ActiveRecord::Base
|
|
58
|
+
phone_format :phone
|
|
59
|
+
phone_format :phone_without_getter, getter: false
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
<pre>
|
|
64
|
+
m = MyModel.new(phone: "(213) 222-2222", phone_without_getter: "(213) 222-2222")
|
|
65
|
+
m.name(true) #=> "2132222222"
|
|
66
|
+
m.name #=> "222-222-2222"
|
|
67
|
+
m.phone_without_getter #=> "2132222222"
|
|
68
|
+
</pre>
|
|
69
|
+
|
|
70
|
+
You can supply your own getter or setter like `in_format` if the defaults don't match your needs or you can pass a getter or setter with `false` to exclude it.
|
|
71
|
+
|
|
72
|
+
### ssn_format
|
|
73
|
+
|
|
74
|
+
`ssn_format` works much like `phone_format`, also accepts custom getters/setters.
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
class MyModel < ActiveRecord::Base
|
|
78
|
+
ssn_format :ssn
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
or with `attr_encrypted`
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
class MyModel < ActiveRecord::Base
|
|
86
|
+
attr_encrypted :ssn # defined before call to ssn_format
|
|
87
|
+
ssn_format :ssn, use_accessor: true
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
<pre>
|
|
92
|
+
m = MyModel.new(ssn: "123 45 6789")
|
|
93
|
+
m.name(true) #=> "123456789"
|
|
94
|
+
m.name #=> "123-45-6789"
|
|
95
|
+
</pre>
|
|
96
|
+
|
|
97
|
+
## Reccomendations
|
|
98
|
+
|
|
99
|
+
If you have getters/setters you would like to re-use across many attributes or classes I would stick em all in a (well-tested) module and keep an eye out for edge cases. You can also use `in_format` as the base for your own custom methods like `phone_format`, etc.
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
module MyFormatters
|
|
103
|
+
CAPS = -> v { |v| v ? v.to_s.capitalize : "Generic Dog Name" }
|
|
104
|
+
NO_CATS = lambda do |v|
|
|
105
|
+
if v =~ /cat/
|
|
106
|
+
v.gsub("cat", "")
|
|
107
|
+
else
|
|
108
|
+
v
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
class MyModel < ActiveRecord::Base
|
|
114
|
+
in_format :dog_name, setter: MyFormatters::NO_CATS, getter: MyFormatters::CAPS
|
|
115
|
+
end
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Upcoming
|
|
119
|
+
|
|
120
|
+
Currently this is written specifically for ActiveRecord but I hope to make it compatible with more ORMs. In the meantime you can use the alias option and it should work with any ruby class.
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
* Freely distributable and licensed under the [MIT license](http://cfarajpour.mit-license.org/license.html).
|
|
125
|
+
* Copyright (c) 2012 Cyrus Farajpour (smoils@gmail.com) [](http://coderwall.com/smoil)
|
data/Rakefile
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
begin
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
6
|
+
end
|
|
7
|
+
begin
|
|
8
|
+
require 'rdoc/task'
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require 'rdoc/rdoc'
|
|
11
|
+
require 'rake/rdoctask'
|
|
12
|
+
RDoc::Task = Rake::RDocTask
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
17
|
+
rdoc.title = 'InFormat'
|
|
18
|
+
rdoc.options << '--line-numbers'
|
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Bundler::GemHelper.install_tasks
|
|
25
|
+
|
|
26
|
+
require 'rake/testtask'
|
|
27
|
+
|
|
28
|
+
require 'rspec/core/rake_task'
|
|
29
|
+
|
|
30
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
31
|
+
task :default => :spec
|
data/lib/in_format.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module InFormat
|
|
2
|
+
|
|
3
|
+
def in_format(attribute, opts = {})
|
|
4
|
+
|
|
5
|
+
if opts[:setter]
|
|
6
|
+
if opts[:use_accessor]
|
|
7
|
+
original_setter = self.instance_method("#{attribute}=")
|
|
8
|
+
|
|
9
|
+
define_method("#{attribute}=") do |value|
|
|
10
|
+
original_setter.bind(self).call(opts[:setter].call(value))
|
|
11
|
+
end
|
|
12
|
+
else
|
|
13
|
+
define_method("#{attribute}=") do |value|
|
|
14
|
+
self[attribute.to_sym] = opts[:setter].call(value)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if opts[:getter]
|
|
20
|
+
if opts[:use_accessor]
|
|
21
|
+
original_getter = self.instance_method(attribute)
|
|
22
|
+
|
|
23
|
+
define_method("#{attribute}") do |raw = false|
|
|
24
|
+
if raw
|
|
25
|
+
original_getter.bind(self).call
|
|
26
|
+
else
|
|
27
|
+
opts[:getter].call(original_getter.bind(self).call)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
define_method("#{attribute}") do |raw = false|
|
|
32
|
+
if raw
|
|
33
|
+
self[attribute.to_sym]
|
|
34
|
+
else
|
|
35
|
+
opts[:getter].call(self[attribute.to_sym])
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module InFormat
|
|
2
|
+
|
|
3
|
+
def phone_format(attribute, opts = {})
|
|
4
|
+
opts[:setter] = Formatters::Phone::DEFAULT_SETTER unless opts.keys.include? :setter
|
|
5
|
+
opts[:getter] = Formatters::Phone::DEFAULT_GETTER unless opts.keys.include? :getter
|
|
6
|
+
|
|
7
|
+
in_format(attribute, opts)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Formatters
|
|
11
|
+
module Phone
|
|
12
|
+
|
|
13
|
+
DEFAULT_SETTER = lambda { |value| value.to_s.gsub(/[^\d|x]/, "") }
|
|
14
|
+
|
|
15
|
+
DEFAULT_GETTER = lambda do |value|
|
|
16
|
+
if value =~ /^\d{10,13}(x\d+)?$/
|
|
17
|
+
num, ext = value.split("x")
|
|
18
|
+
opts = { extension: ext }
|
|
19
|
+
opts.merge!(country_code: num[0..-11]) if num.length > 10
|
|
20
|
+
fmt = number_to_phone(num[(-1 * [num.length, 10].min)..-1].to_i, opts).to_s
|
|
21
|
+
fmt.gsub(" x "," x").gsub("+","")
|
|
22
|
+
else
|
|
23
|
+
value
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
# this is a slightly modified version taken from Rails ActionView::Helpers::NumberHelper
|
|
30
|
+
# credit belongs to the many people who have worked on that project
|
|
31
|
+
# code is released under the MIT License, matching the license used for this project
|
|
32
|
+
def self.number_to_phone(number, options = {})
|
|
33
|
+
return unless number
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
Float(number)
|
|
37
|
+
rescue ArgumentError, TypeError
|
|
38
|
+
raise InvalidNumberError, number
|
|
39
|
+
end if options[:raise]
|
|
40
|
+
|
|
41
|
+
number = number.to_s.strip
|
|
42
|
+
options = options.symbolize_keys
|
|
43
|
+
area_code = options[:area_code]
|
|
44
|
+
delimiter = options[:delimiter] || "-"
|
|
45
|
+
extension = options[:extension]
|
|
46
|
+
country_code = options[:country_code]
|
|
47
|
+
|
|
48
|
+
if area_code
|
|
49
|
+
number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
|
|
50
|
+
else
|
|
51
|
+
number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
|
|
52
|
+
number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
str = []
|
|
56
|
+
str << "+#{country_code}#{delimiter}" unless country_code.blank?
|
|
57
|
+
str << number
|
|
58
|
+
str << " x #{extension}" unless extension.blank?
|
|
59
|
+
str.join
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module InFormat
|
|
2
|
+
|
|
3
|
+
def ssn_format(attribute, opts = {})
|
|
4
|
+
opts[:setter] = Formatters::Ssn::DEFAULT_SETTER unless opts.keys.include? :setter
|
|
5
|
+
opts[:getter] = Formatters::Ssn::DEFAULT_GETTER unless opts.keys.include? :getter
|
|
6
|
+
|
|
7
|
+
in_format(attribute, opts)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Formatters
|
|
11
|
+
module Ssn
|
|
12
|
+
|
|
13
|
+
DEFAULT_SETTER = lambda { |value| value.to_s.gsub(/[^\d]/, "") }
|
|
14
|
+
|
|
15
|
+
DEFAULT_GETTER = lambda do |value|
|
|
16
|
+
if value =~ /^\d{9}\z/
|
|
17
|
+
"#{value[0..2]}-#{value[3..4]}-#{value[5..8]}"
|
|
18
|
+
else
|
|
19
|
+
value
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: in_format
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Cyrus Farajpour
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-03-18 00:00:00.000000000Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rails
|
|
16
|
+
requirement: &70199367255320 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '3'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *70199367255320
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: sqlite3
|
|
27
|
+
requirement: &70199367254520 !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ! '>='
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: *70199367254520
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: rspec-rails
|
|
38
|
+
requirement: &70199367253680 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ~>
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: 2.8.1
|
|
44
|
+
type: :development
|
|
45
|
+
prerelease: false
|
|
46
|
+
version_requirements: *70199367253680
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: attr_encrypted
|
|
49
|
+
requirement: &70199367252600 !ruby/object:Gem::Requirement
|
|
50
|
+
none: false
|
|
51
|
+
requirements:
|
|
52
|
+
- - ~>
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 1.2.0
|
|
55
|
+
type: :development
|
|
56
|
+
prerelease: false
|
|
57
|
+
version_requirements: *70199367252600
|
|
58
|
+
- !ruby/object:Gem::Dependency
|
|
59
|
+
name: wirble
|
|
60
|
+
requirement: &70199367251740 !ruby/object:Gem::Requirement
|
|
61
|
+
none: false
|
|
62
|
+
requirements:
|
|
63
|
+
- - ! '>='
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
type: :development
|
|
67
|
+
prerelease: false
|
|
68
|
+
version_requirements: *70199367251740
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: awesome_print
|
|
71
|
+
requirement: &70199367250460 !ruby/object:Gem::Requirement
|
|
72
|
+
none: false
|
|
73
|
+
requirements:
|
|
74
|
+
- - ! '>='
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '0'
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: *70199367250460
|
|
80
|
+
description: Easily add custom getter and setter filters for attributes.
|
|
81
|
+
email:
|
|
82
|
+
- smoils@gmail.com
|
|
83
|
+
executables: []
|
|
84
|
+
extensions: []
|
|
85
|
+
extra_rdoc_files: []
|
|
86
|
+
files:
|
|
87
|
+
- lib/in_format/core.rb
|
|
88
|
+
- lib/in_format/formatters/phone.rb
|
|
89
|
+
- lib/in_format/formatters/ssn.rb
|
|
90
|
+
- lib/in_format/formatters.rb
|
|
91
|
+
- lib/in_format/railtie.rb
|
|
92
|
+
- lib/in_format/version.rb
|
|
93
|
+
- lib/in_format.rb
|
|
94
|
+
- LICENSE.txt
|
|
95
|
+
- Rakefile
|
|
96
|
+
- README.md
|
|
97
|
+
homepage: https://github.com/smoil/in_format
|
|
98
|
+
licenses: []
|
|
99
|
+
post_install_message:
|
|
100
|
+
rdoc_options: []
|
|
101
|
+
require_paths:
|
|
102
|
+
- lib
|
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
104
|
+
none: false
|
|
105
|
+
requirements:
|
|
106
|
+
- - ! '>='
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '0'
|
|
109
|
+
segments:
|
|
110
|
+
- 0
|
|
111
|
+
hash: -1601762158341379008
|
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
|
+
none: false
|
|
114
|
+
requirements:
|
|
115
|
+
- - ! '>='
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
segments:
|
|
119
|
+
- 0
|
|
120
|
+
hash: -1601762158341379008
|
|
121
|
+
requirements: []
|
|
122
|
+
rubyforge_project:
|
|
123
|
+
rubygems_version: 1.8.15
|
|
124
|
+
signing_key:
|
|
125
|
+
specification_version: 3
|
|
126
|
+
summary: Easily add custom getter and setter filters for attributes.
|
|
127
|
+
test_files: []
|