vacuum_cleaner 0.5.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +19 -11
- data/init.rb +1 -1
- data/lib/vacuum_cleaner.rb +7 -3
- data/lib/vacuum_cleaner/normalizations.rb +28 -2
- data/lib/vacuum_cleaner/normalizations/method.rb +4 -7
- data/lib/vacuum_cleaner/normalizations/url.rb +22 -1
- data/lib/vacuum_cleaner/normalizer.rb +3 -3
- data/rails/init.rb +1 -2
- data/test/integration/active_record_integration_test.rb +67 -0
- data/test/test_helper.rb +0 -7
- data/test/unit/vacuum_cleaner/normalizations/method_test.rb +5 -0
- data/test/unit/vacuum_cleaner/normalizations/url_test.rb +9 -0
- metadata +7 -19
data/Rakefile
CHANGED
@@ -3,22 +3,13 @@ require 'rake/testtask'
|
|
3
3
|
|
4
4
|
require File.join(File.dirname(__FILE__), 'lib', 'vacuum_cleaner')
|
5
5
|
|
6
|
-
task :default => :test
|
7
|
-
|
8
|
-
desc 'Test the vacuum_cleaner plugin.'
|
9
|
-
Rake::TestTask.new(:test) do |t|
|
10
|
-
t.libs << 'lib'
|
11
|
-
t.libs << 'test'
|
12
|
-
t.pattern = 'test/**/*_test.rb'
|
13
|
-
t.verbose = true
|
14
|
-
end
|
15
|
-
|
16
6
|
begin
|
17
7
|
require 'yard'
|
18
8
|
desc 'Generate documentation for vacuum_cleaner. (requires yard)'
|
19
9
|
YARD::Rake::YardocTask.new(:doc) do |t|
|
20
10
|
t.files = ['lib/**/*.rb']
|
21
11
|
t.options = [
|
12
|
+
"--no-private",
|
22
13
|
"--readme", "README.md",
|
23
14
|
"--title", "vacuum_cleaner (v#{VacuumCleaner::VERSION}) API Documentation"
|
24
15
|
]
|
@@ -42,7 +33,6 @@ begin
|
|
42
33
|
gemspec.extra_rdoc_files = %w{README.md}
|
43
34
|
|
44
35
|
gemspec.add_development_dependency('shoulda', '>= 2.10.2')
|
45
|
-
gemspec.add_development_dependency('rr', '>= 0.10.5')
|
46
36
|
gemspec.add_development_dependency('activesupport', '>= 2.3.5')
|
47
37
|
|
48
38
|
gemspec.files.reject! { |file| file =~ /\.gemspec$/ } # kinda redundant
|
@@ -59,6 +49,24 @@ task :clean do |t|
|
|
59
49
|
FileUtils.rm_rf ".yardoc"
|
60
50
|
end
|
61
51
|
|
52
|
+
namespace :test do
|
53
|
+
desc 'Test the vacuum_cleaner plugin.'
|
54
|
+
Rake::TestTask.new(:unit) do |t|
|
55
|
+
t.libs << 'test'
|
56
|
+
t.pattern = 'test/unit/**/*_test.rb'
|
57
|
+
t.verbose = true
|
58
|
+
end
|
59
|
+
|
60
|
+
desc 'Run integration tests for the vacuum_cleaner plugin.'
|
61
|
+
Rake::TestTask.new(:integration) do |t|
|
62
|
+
t.libs << 'test'
|
63
|
+
t.pattern = 'test/integration/**/*_test.rb'
|
64
|
+
t.verbose = true
|
65
|
+
end
|
66
|
+
|
67
|
+
task :all => [:'test:unit', :'test:integration']
|
68
|
+
end
|
69
|
+
|
62
70
|
namespace :metrics do
|
63
71
|
desc 'Report all metrics, i.e. stats and code coverage.'
|
64
72
|
task :all => [:stats, :coverage]
|
data/init.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require File.dirname(__FILE__)
|
1
|
+
require File.join(File.dirname(__FILE__), 'rails', 'init')
|
data/lib/vacuum_cleaner.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
# Fancy value normalization utility for ruby (and rails)
|
1
|
+
# Fancy value normalization utility for ruby (and rails),
|
2
|
+
# see {VacuumCleaner::Normalizations} for more information about usage.
|
3
|
+
#
|
4
|
+
# @see VacuumCleaner::Normalizations
|
5
|
+
# @see VacuumCleaner::Normalizer
|
2
6
|
module VacuumCleaner
|
3
|
-
# +VacuumCleaner+ version
|
4
|
-
VERSION = "0.
|
7
|
+
# +VacuumCleaner+ version
|
8
|
+
VERSION = "1.0.0".freeze
|
5
9
|
|
6
10
|
autoload :Normalizer, 'vacuum_cleaner/normalizer'
|
7
11
|
autoload :Normalizations, 'vacuum_cleaner/normalizations'
|
@@ -1,7 +1,11 @@
|
|
1
1
|
module VacuumCleaner
|
2
|
+
|
3
|
+
# @private
|
2
4
|
# Suffix added to existing setter methods
|
3
5
|
WITHOUT_NORMALIZATION_SUFFIX = "_without_normalization"
|
4
6
|
|
7
|
+
# Base module required to be included in
|
8
|
+
#
|
5
9
|
module Normalizations
|
6
10
|
|
7
11
|
def self.included(base)
|
@@ -9,6 +13,27 @@ module VacuumCleaner
|
|
9
13
|
end
|
10
14
|
|
11
15
|
module ClassMethods
|
16
|
+
|
17
|
+
# Enables normalization chain for supplied attributes.
|
18
|
+
#
|
19
|
+
# @example Basic usage for plain old ruby objects.
|
20
|
+
# class Doctor
|
21
|
+
# include VacuumCleaner::Normalizations
|
22
|
+
# attr_accessor :name
|
23
|
+
# normalizes :name
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
#
|
27
|
+
# @param [Strings, Symbols] attributes list of attribute names to normalize, at least one attribute is required
|
28
|
+
# @param [Hash] options optional list of normalizers to use, like +:downcase => true+. To not run the default
|
29
|
+
# normalizer ({VacuumCleaner::Normalizer#normalize_value}) set +:default => false+
|
30
|
+
#
|
31
|
+
# @yield [value] optional block to define some one-time custom normalization logic
|
32
|
+
# @yieldparam value can be +nil+, otherwise value as passed through the default normalizer
|
33
|
+
# @yieldreturn should return value as normalized by the block
|
34
|
+
#
|
35
|
+
# @yield [instance, attribute, value] optional (extended) block with all arguments, like the +object+ and
|
36
|
+
# current +attribute+ name. Everything else behaves the same es the single-value +yield+
|
12
37
|
def normalizes(*attributes, &block)
|
13
38
|
metaklass = class << self; self; end
|
14
39
|
|
@@ -38,8 +63,8 @@ module VacuumCleaner
|
|
38
63
|
rb_src = <<-RUBY
|
39
64
|
def #{attribute}=(value) # 1. def name=(value)
|
40
65
|
value = send(:'normalize_#{attribute}', value) # 2. value = send(:'normalize_name', value)
|
41
|
-
return send(#{original_setter.inspect}, value) if respond_to?(#{original_setter.inspect}) # 3. return send(:'
|
42
|
-
return
|
66
|
+
return send(#{original_setter.inspect}, value) if respond_to?(#{original_setter.inspect}) # 3. return send(:'name_wi...=', value) if respond_to?(:'name_wi...=')
|
67
|
+
return self[#{attribute.inspect}] = value if respond_to?(:[]=) # 4. return self[:name] = value if respond_to?(:write_attribute)
|
43
68
|
@#{attribute} = value # 5. @name = value
|
44
69
|
end # 6. end
|
45
70
|
RUBY
|
@@ -50,6 +75,7 @@ module VacuumCleaner
|
|
50
75
|
end
|
51
76
|
end
|
52
77
|
|
78
|
+
# @private
|
53
79
|
# Okay, because this library currently does not depend on
|
54
80
|
# <tt>ActiveSupport</tt> or anything similar an "independent" camelizing process is
|
55
81
|
# required.
|
@@ -13,10 +13,7 @@ module VacuumCleaner
|
|
13
13
|
# Subclasses of the +MethodNormalizer+ can take advantage of it's
|
14
14
|
# +normalize_if_respond_to+ method, to easily create custom
|
15
15
|
# normalizers based on methods availble on the result value.
|
16
|
-
class MethodNormalizer < Normalizer
|
17
|
-
# Ensure access to default normalization method
|
18
|
-
alias_method :default_normalize_value, :normalize_value
|
19
|
-
|
16
|
+
class MethodNormalizer < Normalizer
|
20
17
|
# Helper method to "bake" a method normalizer from a method, enabling us to do stuff like.
|
21
18
|
#
|
22
19
|
# TitelizeNormalizer = MethodNormalizer.build(:titleize)
|
@@ -31,11 +28,11 @@ module VacuumCleaner
|
|
31
28
|
super(args)
|
32
29
|
end
|
33
30
|
|
34
|
-
# Normalize value by
|
35
|
-
#
|
31
|
+
# Normalize value by trying to call the method at hand, if
|
32
|
+
# +value+ does not respond to the defined method, returns +nil+.
|
36
33
|
def normalize_value(value)
|
37
34
|
sym = options[:method]
|
38
|
-
value.respond_to?(sym) ? value.send(sym) :
|
35
|
+
value.respond_to?(sym) ? value.send(sym) : nil
|
39
36
|
end
|
40
37
|
end
|
41
38
|
|
@@ -1,17 +1,38 @@
|
|
1
1
|
module VacuumCleaner
|
2
2
|
module Normalizations
|
3
3
|
|
4
|
-
#
|
4
|
+
# Normalizer which is used to prefix strings with a scheme, if missing.
|
5
|
+
# This is useful to ensure, that an input field always has e.g. the
|
6
|
+
# "http://" scheme added. Please note, that this normalizer does not
|
7
|
+
# validate a URL in any way.
|
5
8
|
#
|
9
|
+
# normalizes :homepage, :url => true
|
6
10
|
#
|
11
|
+
# Accepts a string as input, so to normalize for instance FTP URLs.
|
12
|
+
#
|
13
|
+
# normalizes :download_url, :url => "ftp://"
|
14
|
+
#
|
15
|
+
# To make further customizations, the constructor accepts a hash.
|
16
|
+
#
|
17
|
+
# normalizes, :contact_url, :url => { :scheme => "http://",
|
18
|
+
# :unless => %r{\A(https?://|xmpp:|gtalk:|mailto:)} }
|
19
|
+
#
|
20
|
+
# The key <tt>:scheme</tt> is always used as the prefix, when the input
|
21
|
+
# does not a match the regex in <tt>:unless</tt>.
|
7
22
|
class UrlNormalizer < Normalizer
|
23
|
+
|
24
|
+
# Accepts either a hash or a string.
|
8
25
|
def initialize(options = {})
|
9
26
|
options = { :scheme => "http://", :unless => %r{\Ahttps?://}i } if options.nil? || options.empty?
|
10
27
|
options = { :scheme => options, :unless => %r{\A#{options}}i } unless options.is_a?(Hash)
|
11
28
|
super(options)
|
12
29
|
end
|
13
30
|
|
31
|
+
# Prefixes input with <tt>options[:scheme]</tt> if it doesn't matches
|
32
|
+
# <tt>options[:unless]</tt>.
|
14
33
|
def normalize_value(value)
|
34
|
+
value = super # just ensure that default stripping/cleaning is done already
|
35
|
+
return nil if value == options[:scheme]
|
15
36
|
value =~ options[:unless] ? value : "#{options[:scheme]}#{value}" unless value.nil?
|
16
37
|
end
|
17
38
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module VacuumCleaner
|
1
|
+
module VacuumCleaner
|
2
2
|
|
3
3
|
# A small base class for implementing custom value normalizers.
|
4
4
|
# Might seem like a slight overkill, yet makes the library pretty
|
@@ -46,7 +46,7 @@ module VacuumCleaner #:nodoc:
|
|
46
46
|
# +normalize_value+.
|
47
47
|
#
|
48
48
|
# This can be used together with the +normalizes+ method (see
|
49
|
-
#
|
49
|
+
# VacuumCleaner::Normalizers#normalizes for more on this).
|
50
50
|
class Normalizer
|
51
51
|
# Options as supplied to the normalizer.
|
52
52
|
attr_reader :options
|
@@ -59,7 +59,7 @@ module VacuumCleaner #:nodoc:
|
|
59
59
|
# Only override this method if access to the <tt>object</tt> or <tt>attribute</tt> name
|
60
60
|
# is required, else override +normalize_value+, makes life much simpler :)
|
61
61
|
#
|
62
|
-
# Default behaviour just calls
|
62
|
+
# Default behaviour just calls #normalize_value.
|
63
63
|
def normalize(object, attribute, value); normalize_value(value) end
|
64
64
|
|
65
65
|
# Override this method in subclasses to specifiy custom normalization steps and magic.
|
data/rails/init.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
1
|
require 'vacuum_cleaner'
|
2
2
|
|
3
|
-
ActiveRecord::Base.class_eval { include VacuumCleaner::Normalizations } # all versions of rails
|
4
|
-
# ActiveModel::Base.class_eval { include VacuumCleaner::Normalizations } if defined?(ActiveModel::Base) # Rails 3+
|
3
|
+
ActiveRecord::Base.class_eval { include VacuumCleaner::Normalizations } if defined?(ActiveRecord::Base) # all versions of rails
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# load ActiveRecord
|
4
|
+
require 'active_record'
|
5
|
+
|
6
|
+
# open connection to in-memory db
|
7
|
+
ActiveRecord::Base.establish_connection({
|
8
|
+
:adapter => RUBY_PLATFORM =~ /java/ ? 'jdbcsqlite3' : 'sqlite3',
|
9
|
+
:database => ':memory:'})
|
10
|
+
|
11
|
+
# run init.rb
|
12
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'init')
|
13
|
+
|
14
|
+
puts "Running integration tests against: active_record-#{ActiveRecord::VERSION::STRING}"
|
15
|
+
|
16
|
+
class ActiveRecordIntegrationTest < ::Test::Unit::TestCase
|
17
|
+
context "ActiveRecord::Base" do
|
18
|
+
should "include VacuumCleaner::Normalizations" do
|
19
|
+
assert ActiveRecord::Base.included_modules.include?(VacuumCleaner::Normalizations)
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with a sqlite connection" do
|
23
|
+
setup do
|
24
|
+
# build db
|
25
|
+
ActiveRecord::Base.connection.create_table :dummies, :force => true do |t|
|
26
|
+
t.column :name, :string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
should "respond to normalize and normalize :name on set" do
|
31
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; normalizes :name end
|
32
|
+
|
33
|
+
object = klass.new({ :name => "Elliot Reid\n" })
|
34
|
+
assert_equal "Elliot Reid", object.name
|
35
|
+
end
|
36
|
+
|
37
|
+
should "normalize on +object.name+ accessors as well" do
|
38
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; normalizes :name end
|
39
|
+
|
40
|
+
object = klass.new
|
41
|
+
object.name = " Dorian\t\n"
|
42
|
+
assert_equal "Dorian", object.name
|
43
|
+
end
|
44
|
+
|
45
|
+
should "not normalize when accessing directly using []/write_attribute" do
|
46
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; normalizes :name end
|
47
|
+
object = klass.new
|
48
|
+
object[:name] = "Elliot Reid\n\t"
|
49
|
+
assert_equal "Elliot Reid\n\t", object.name
|
50
|
+
end
|
51
|
+
|
52
|
+
should "not normalize when reading from database" do
|
53
|
+
ActiveRecord::Base.connection.execute "INSERT INTO dummies VALUES(NULL,'Elliot Reid\n\t');"
|
54
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; normalizes :name end
|
55
|
+
assert_equal "Elliot Reid\n\t", klass.last.name
|
56
|
+
end
|
57
|
+
|
58
|
+
should "work with customized setter methods, masking AR-attributes" do
|
59
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; def name=(n); self[:name] = n; end; normalizes :name end
|
60
|
+
object = klass.new :name => " J.D.\n"
|
61
|
+
assert_equal "J.D.", object.name
|
62
|
+
object.name = "Dorian\n\r"
|
63
|
+
assert_equal "Dorian", object.name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -17,6 +17,11 @@ class VacuumCleaner::Normalizations::MethodTest < Test::Unit::TestCase
|
|
17
17
|
assert_equal "ELLIOT\n", upcaser.normalize_value("Elliot\n")
|
18
18
|
assert_equal " \t", upcaser.normalize_value(" \t")
|
19
19
|
end
|
20
|
+
|
21
|
+
should "convert value to <nil> if object does not respond to supplied method" do
|
22
|
+
normalizer = MethodNormalizer.new(:this_method_does_certainly_not_exist)
|
23
|
+
assert_nil normalizer.normalize_value("Elliot")
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
22
27
|
context "DowncaseNormalizer#normalize_value" do
|
@@ -35,5 +35,14 @@ class VacuumCleaner::Normalizations::UrlTest < Test::Unit::TestCase
|
|
35
35
|
assert_equal "jabber:jd@sh.com", n.normalize_value("jabber:jd@sh.com")
|
36
36
|
assert_equal "https://docs.google.com", n.normalize_value("https://docs.google.com")
|
37
37
|
end
|
38
|
+
|
39
|
+
should "normalize to <nil> if only scheme is given" do
|
40
|
+
assert_nil UrlNormalizer.new.normalize_value("http://")
|
41
|
+
assert_nil UrlNormalizer.new.normalize_value(" http://\n")
|
42
|
+
end
|
43
|
+
|
44
|
+
should "be stupid, so if some other scheme is used, just override it, haha" do
|
45
|
+
assert_equal "xmpp:mailto:jd@sacred-heart.com", UrlNormalizer.new("xmpp:").normalize_value("mailto:jd@sacred-heart.com")
|
46
|
+
end
|
38
47
|
end
|
39
48
|
end
|
metadata
CHANGED
@@ -3,10 +3,10 @@ name: vacuum_cleaner
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
+
- 1
|
6
7
|
- 0
|
7
|
-
- 5
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 1.0.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Lukas Westermann
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-04-21 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -31,24 +31,10 @@ dependencies:
|
|
31
31
|
version: 2.10.2
|
32
32
|
type: :development
|
33
33
|
version_requirements: *id001
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
|
-
name: rr
|
36
|
-
prerelease: false
|
37
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
segments:
|
42
|
-
- 0
|
43
|
-
- 10
|
44
|
-
- 5
|
45
|
-
version: 0.10.5
|
46
|
-
type: :development
|
47
|
-
version_requirements: *id002
|
48
34
|
- !ruby/object:Gem::Dependency
|
49
35
|
name: activesupport
|
50
36
|
prerelease: false
|
51
|
-
requirement: &
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
52
38
|
requirements:
|
53
39
|
- - ">="
|
54
40
|
- !ruby/object:Gem::Version
|
@@ -58,7 +44,7 @@ dependencies:
|
|
58
44
|
- 5
|
59
45
|
version: 2.3.5
|
60
46
|
type: :development
|
61
|
-
version_requirements: *
|
47
|
+
version_requirements: *id002
|
62
48
|
description: Ruby (and Rails) attribute cleaning support, provides some nice and easy to enhance default normalization strategies.
|
63
49
|
email: lukas.westermann@gmail.com
|
64
50
|
executables: []
|
@@ -79,6 +65,7 @@ files:
|
|
79
65
|
- lib/vacuum_cleaner/normalizations/url.rb
|
80
66
|
- lib/vacuum_cleaner/normalizer.rb
|
81
67
|
- rails/init.rb
|
68
|
+
- test/integration/active_record_integration_test.rb
|
82
69
|
- test/test_helper.rb
|
83
70
|
- test/unit/vacuum_cleaner/normalizations/method_test.rb
|
84
71
|
- test/unit/vacuum_cleaner/normalizations/url_test.rb
|
@@ -115,6 +102,7 @@ signing_key:
|
|
115
102
|
specification_version: 3
|
116
103
|
summary: Ruby (and Rails) attribute cleaning support, provides some nice default normalization strategies.
|
117
104
|
test_files:
|
105
|
+
- test/integration/active_record_integration_test.rb
|
118
106
|
- test/test_helper.rb
|
119
107
|
- test/unit/vacuum_cleaner/normalizations/method_test.rb
|
120
108
|
- test/unit/vacuum_cleaner/normalizations/url_test.rb
|