dm-types 0.10.2 → 1.0.0.rc1
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 +36 -0
- data/Gemfile +147 -0
- data/Rakefile +7 -8
- data/VERSION +1 -1
- data/dm-types.gemspec +61 -20
- data/lib/dm-types.rb +24 -19
- data/lib/dm-types/bcrypt_hash.rb +17 -13
- data/lib/dm-types/comma_separated_list.rb +11 -16
- data/lib/dm-types/csv.rb +11 -11
- data/lib/dm-types/enum.rb +33 -50
- data/lib/dm-types/epoch_time.rb +11 -11
- data/lib/dm-types/file_path.rb +13 -10
- data/lib/dm-types/flag.rb +17 -25
- data/lib/dm-types/ip_address.rb +15 -11
- data/lib/dm-types/json.rb +17 -14
- data/lib/dm-types/paranoid/base.rb +38 -0
- data/lib/dm-types/paranoid_boolean.rb +23 -0
- data/lib/dm-types/paranoid_datetime.rb +22 -0
- data/lib/dm-types/regexp.rb +8 -8
- data/lib/dm-types/slug.rb +7 -12
- data/lib/dm-types/uri.rb +21 -9
- data/lib/dm-types/uuid.rb +18 -11
- data/lib/dm-types/yaml.rb +12 -10
- data/spec/fixtures/article.rb +0 -2
- data/spec/fixtures/bookmark.rb +0 -2
- data/spec/fixtures/network_node.rb +0 -2
- data/spec/fixtures/person.rb +0 -2
- data/spec/fixtures/software_package.rb +0 -2
- data/spec/fixtures/ticket.rb +2 -4
- data/spec/fixtures/tshirt.rb +3 -5
- data/spec/integration/bcrypt_hash_spec.rb +33 -31
- data/spec/integration/comma_separated_list_spec.rb +55 -53
- data/spec/integration/enum_spec.rb +55 -53
- data/spec/integration/file_path_spec.rb +105 -103
- data/spec/integration/flag_spec.rb +42 -40
- data/spec/integration/ip_address_spec.rb +91 -89
- data/spec/integration/json_spec.rb +41 -39
- data/spec/integration/slug_spec.rb +36 -34
- data/spec/integration/uri_spec.rb +82 -79
- data/spec/integration/uuid_spec.rb +63 -61
- data/spec/integration/yaml_spec.rb +37 -35
- data/spec/spec_helper.rb +7 -36
- data/spec/unit/bcrypt_hash_spec.rb +18 -10
- data/spec/unit/csv_spec.rb +92 -80
- data/spec/unit/enum_spec.rb +27 -42
- data/spec/unit/epoch_time_spec.rb +18 -7
- data/spec/unit/file_path_spec.rb +15 -10
- data/spec/unit/flag_spec.rb +13 -36
- data/spec/unit/ip_address_spec.rb +13 -10
- data/spec/unit/json_spec.rb +21 -14
- data/spec/unit/paranoid_boolean_spec.rb +138 -0
- data/spec/unit/paranoid_datetime_spec.rb +143 -0
- data/spec/unit/regexp_spec.rb +15 -5
- data/spec/unit/uri_spec.rb +13 -9
- data/spec/unit/yaml_spec.rb +16 -9
- data/tasks/local_gemfile.rake +18 -0
- data/tasks/spec.rake +0 -3
- metadata +122 -52
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'dm-types/paranoid/base'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
class Property
|
5
|
+
class ParanoidDateTime < DateTime
|
6
|
+
lazy true
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
def bind
|
10
|
+
property_name = name.inspect
|
11
|
+
|
12
|
+
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
13
|
+
include Paranoid::Base
|
14
|
+
|
15
|
+
set_paranoid_property(#{property_name}) { ::DateTime.now }
|
16
|
+
|
17
|
+
default_scope(#{repository_name.inspect}).update(#{property_name} => nil)
|
18
|
+
RUBY
|
19
|
+
end
|
20
|
+
end # class ParanoidDateTime
|
21
|
+
end # module Property
|
22
|
+
end # module DataMapper
|
data/lib/dm-types/regexp.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
|
2
|
-
module Types
|
3
|
-
class Regexp < DataMapper::Type
|
4
|
-
primitive String
|
1
|
+
require 'dm-core'
|
5
2
|
|
6
|
-
|
3
|
+
module DataMapper
|
4
|
+
class Property
|
5
|
+
class Regexp < String
|
6
|
+
def load(value)
|
7
7
|
::Regexp.new(value) unless value.nil?
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def dump(value)
|
11
11
|
value.source unless value.nil?
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
load(value
|
14
|
+
def typecast(value)
|
15
|
+
load(value)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
data/lib/dm-types/slug.rb
CHANGED
@@ -1,20 +1,15 @@
|
|
1
|
+
require 'dm-core'
|
1
2
|
require 'stringex'
|
2
3
|
|
3
4
|
module DataMapper
|
4
|
-
|
5
|
-
class Slug <
|
6
|
-
primitive String
|
7
|
-
length 2000
|
8
|
-
|
5
|
+
class Property
|
6
|
+
class Slug < String
|
9
7
|
# Maximum length chosen because URI type is limited to 2000
|
10
8
|
# characters, and a slug is a component of a URI, so it should
|
11
9
|
# not exceed the maximum URI length either.
|
10
|
+
length 2000
|
12
11
|
|
13
|
-
def
|
14
|
-
value
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.dump(value, property)
|
12
|
+
def dump(value)
|
18
13
|
return if value.nil?
|
19
14
|
|
20
15
|
if value.respond_to?(:to_str)
|
@@ -24,9 +19,9 @@ module DataMapper
|
|
24
19
|
end
|
25
20
|
end
|
26
21
|
|
27
|
-
def
|
22
|
+
def escape(string)
|
28
23
|
string.to_url
|
29
24
|
end
|
30
25
|
end # class Slug
|
31
|
-
end #
|
26
|
+
end # class Property
|
32
27
|
end # module DataMapper
|
data/lib/dm-types/uri.rb
CHANGED
@@ -1,25 +1,37 @@
|
|
1
1
|
require 'addressable/uri'
|
2
|
+
require 'dm-core'
|
2
3
|
|
3
4
|
module DataMapper
|
4
|
-
|
5
|
-
class URI <
|
6
|
-
|
7
|
-
|
5
|
+
class Property
|
6
|
+
class URI < String
|
7
|
+
length 2000
|
8
|
+
|
9
|
+
def custom?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def primitive?(value)
|
14
|
+
value.kind_of?(Addressable::URI)
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?(value, negated = false)
|
18
|
+
super || primitive?(value) || value.kind_of?(::String)
|
19
|
+
end
|
8
20
|
|
9
21
|
# Maximum length chosen based on recommendation:
|
10
22
|
# http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-an-url
|
11
23
|
|
12
|
-
def
|
24
|
+
def load(value)
|
13
25
|
Addressable::URI.parse(value)
|
14
26
|
end
|
15
27
|
|
16
|
-
def
|
28
|
+
def dump(value)
|
17
29
|
value.to_s unless value.nil?
|
18
30
|
end
|
19
31
|
|
20
|
-
def
|
21
|
-
load(value
|
32
|
+
def typecast_to_primitive(value)
|
33
|
+
load(value)
|
22
34
|
end
|
23
35
|
end # class URI
|
24
|
-
end #
|
36
|
+
end # class Property
|
25
37
|
end # module DataMapper
|
data/lib/dm-types/uuid.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
require 'dm-core'
|
1
2
|
require 'uuidtools' # must be ~>2.0
|
2
3
|
|
3
4
|
module DataMapper
|
4
|
-
|
5
|
+
class Property
|
5
6
|
# UUID Type
|
6
7
|
# First run at this, because I need it. A few caveats:
|
7
8
|
# * Only works on postgres, using the built-in native uuid type.
|
@@ -37,25 +38,31 @@ module DataMapper
|
|
37
38
|
#
|
38
39
|
# -- benburkert Nov 15, 08
|
39
40
|
#
|
40
|
-
class UUID <
|
41
|
-
|
42
|
-
length 36
|
41
|
+
class UUID < String
|
42
|
+
length 36
|
43
43
|
|
44
|
-
|
45
|
-
|
44
|
+
# We need to override this method otherwise typecast_to_primitive won't be called.
|
45
|
+
# In the future we will set primitive to UUIDTools::UUID but this can happen only
|
46
|
+
# when adapters can handle it
|
47
|
+
def primitive?(value)
|
48
|
+
value.kind_of?(UUIDTools::UUID)
|
46
49
|
end
|
47
50
|
|
48
|
-
def
|
51
|
+
def dump(value)
|
49
52
|
value.to_s unless value.nil?
|
50
53
|
end
|
51
54
|
|
52
|
-
def
|
53
|
-
if
|
55
|
+
def load(value)
|
56
|
+
if primitive?(value)
|
54
57
|
value
|
55
|
-
|
56
|
-
|
58
|
+
elsif !value.nil?
|
59
|
+
UUIDTools::UUID.parse(value)
|
57
60
|
end
|
58
61
|
end
|
62
|
+
|
63
|
+
def typecast_to_primitive(value)
|
64
|
+
load(value)
|
65
|
+
end
|
59
66
|
end
|
60
67
|
end
|
61
68
|
end
|
data/lib/dm-types/yaml.rb
CHANGED
@@ -1,34 +1,36 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'dm-core'
|
2
3
|
|
3
4
|
module DataMapper
|
4
|
-
|
5
|
-
class Yaml <
|
6
|
-
|
5
|
+
class Property
|
6
|
+
class Yaml < Text
|
7
|
+
def custom?
|
8
|
+
true
|
9
|
+
end
|
7
10
|
|
8
|
-
def
|
11
|
+
def load(value)
|
9
12
|
if value.nil?
|
10
13
|
nil
|
11
|
-
elsif value.is_a?(String)
|
14
|
+
elsif value.is_a?(::String)
|
12
15
|
::YAML.load(value)
|
13
16
|
else
|
14
17
|
raise ArgumentError.new("+value+ of a property of YAML type must be nil or a String")
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
|
-
def
|
21
|
+
def dump(value)
|
19
22
|
if value.nil?
|
20
23
|
nil
|
21
|
-
elsif value.is_a?(String) && value =~ /^---/
|
24
|
+
elsif value.is_a?(::String) && value =~ /^---/
|
22
25
|
value
|
23
26
|
else
|
24
27
|
::YAML.dump(value)
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
28
|
-
def
|
29
|
-
# No typecasting; leave values exactly as they're provided.
|
31
|
+
def typecast(value)
|
30
32
|
value
|
31
33
|
end
|
32
34
|
end # class Yaml
|
33
|
-
end #
|
35
|
+
end # class Property
|
34
36
|
end # module DataMapper
|
data/spec/fixtures/article.rb
CHANGED
data/spec/fixtures/bookmark.rb
CHANGED
data/spec/fixtures/person.rb
CHANGED
data/spec/fixtures/ticket.rb
CHANGED
@@ -7,7 +7,7 @@ module DataMapper
|
|
7
7
|
#
|
8
8
|
|
9
9
|
include DataMapper::Resource
|
10
|
-
include DataMapper::
|
10
|
+
include DataMapper::Validations
|
11
11
|
|
12
12
|
#
|
13
13
|
# Properties
|
@@ -16,9 +16,7 @@ module DataMapper
|
|
16
16
|
property :id, Serial
|
17
17
|
property :title, String, :length => 255
|
18
18
|
property :body, Text
|
19
|
-
property :status, Enum[:unconfirmed, :confirmed, :assigned, :resolved, :not_applicable]
|
20
|
-
|
21
|
-
auto_migrate!
|
19
|
+
property :status, Enum, :flags => [:unconfirmed, :confirmed, :assigned, :resolved, :not_applicable]
|
22
20
|
end # Ticket
|
23
21
|
end
|
24
22
|
end
|
data/spec/fixtures/tshirt.rb
CHANGED
@@ -16,12 +16,10 @@ module DataMapper
|
|
16
16
|
property :id, Serial
|
17
17
|
property :writing, String
|
18
18
|
property :has_picture, Boolean, :default => false
|
19
|
-
property :picture, Enum[:octocat, :fork_you, :git_down]
|
19
|
+
property :picture, Enum, :flags => [:octocat, :fork_you, :git_down]
|
20
20
|
|
21
|
-
property :color, Enum[:white, :black, :red, :orange, :yellow, :green, :cyan, :blue, :purple]
|
22
|
-
property :size, Flag[:xs, :small, :medium, :large, :xl, :xxl]
|
23
|
-
|
24
|
-
auto_migrate!
|
21
|
+
property :color, Enum, :flags => [:white, :black, :red, :orange, :yellow, :green, :cyan, :blue, :purple]
|
22
|
+
property :size, Flag, :flags => [:xs, :small, :medium, :large, :xl, :xxl]
|
25
23
|
end # Shirt
|
26
24
|
end # Fixtures
|
27
25
|
end # Types
|
@@ -5,37 +5,39 @@ try_spec do
|
|
5
5
|
require './spec/fixtures/person'
|
6
6
|
|
7
7
|
describe DataMapper::Types::Fixtures::Person do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
8
|
+
supported_by :all do
|
9
|
+
before :all do
|
10
|
+
@resource = DataMapper::Types::Fixtures::Person.create(:password => 'DataMapper R0cks!')
|
11
|
+
DataMapper::Types::Fixtures::Person.create(:password => 'password1')
|
12
|
+
|
13
|
+
@people = DataMapper::Types::Fixtures::Person.all
|
14
|
+
@resource.reload
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'persists the password on initial save' do
|
18
|
+
@resource.password.should == 'DataMapper R0cks!'
|
19
|
+
@people.last.password.should == 'password1'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'recalculates password hash on attribute update' do
|
23
|
+
@resource.attribute_set(:password, 'bcryptic obscure')
|
24
|
+
@resource.save
|
25
|
+
|
26
|
+
@resource.reload
|
27
|
+
@resource.password.should == 'bcryptic obscure'
|
28
|
+
@resource.password.should_not == 'DataMapper R0cks!'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'does not change password value on reload' do
|
32
|
+
resource = @people.last
|
33
|
+
original = resource.password.to_s
|
34
|
+
resource.reload
|
35
|
+
resource.password.to_s.should == original
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'uses cost of BCrypt::Engine::DEFAULT_COST' do
|
39
|
+
@resource.password.cost.should == BCrypt::Engine::DEFAULT_COST
|
40
|
+
end
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -5,83 +5,85 @@ try_spec do
|
|
5
5
|
require './spec/fixtures/person'
|
6
6
|
|
7
7
|
describe DataMapper::Types::Fixtures::Person do
|
8
|
-
|
9
|
-
@resource = DataMapper::Types::Fixtures::Person.new(:name => '')
|
10
|
-
end
|
11
|
-
|
12
|
-
describe 'with no interests information' do
|
8
|
+
supported_by :all do
|
13
9
|
before :all do
|
14
|
-
@resource
|
10
|
+
@resource = DataMapper::Types::Fixtures::Person.new(:name => '')
|
15
11
|
end
|
16
12
|
|
17
|
-
describe '
|
13
|
+
describe 'with no interests information' do
|
18
14
|
before :all do
|
19
|
-
@resource.
|
20
|
-
@resource.reload
|
15
|
+
@resource.interests = nil
|
21
16
|
end
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
describe 'when dumped and loaded again' do
|
19
|
+
before :all do
|
20
|
+
@resource.save.should be_true
|
21
|
+
@resource.reload
|
22
|
+
end
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
it 'has no interests' do
|
25
|
+
@resource.interests.should == nil
|
26
|
+
end
|
27
|
+
end
|
32
28
|
end
|
33
29
|
|
34
|
-
describe '
|
30
|
+
describe 'with no interests information' do
|
35
31
|
before :all do
|
36
|
-
@resource.
|
37
|
-
@resource.reload
|
32
|
+
@resource.interests = []
|
38
33
|
end
|
39
34
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
35
|
+
describe 'when dumped and loaded again' do
|
36
|
+
before :all do
|
37
|
+
@resource.save.should be_true
|
38
|
+
@resource.reload
|
39
|
+
end
|
45
40
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
@resource.save
|
51
|
-
end.should raise_error(ArgumentError, /must be a string, an array or nil/)
|
41
|
+
it 'has empty interests list' do
|
42
|
+
@resource.interests.should == []
|
43
|
+
end
|
44
|
+
end
|
52
45
|
end
|
53
|
-
end
|
54
46
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
47
|
+
describe 'with interests information given as a Hash' do
|
48
|
+
it 'raises ArgumentError' do
|
49
|
+
lambda do
|
50
|
+
@resource.interests = { :hash => 'value' }
|
51
|
+
@resource.save
|
52
|
+
end.should raise_error(ArgumentError, /must be a string, an array or nil/)
|
53
|
+
end
|
59
54
|
end
|
60
55
|
|
61
|
-
describe '
|
56
|
+
describe 'with a few items on the interests list' do
|
62
57
|
before :all do
|
63
|
-
@
|
64
|
-
@resource.
|
58
|
+
@input = 'fire, water, fire, a whole lot of other interesting things, ,,,'
|
59
|
+
@resource.interests = @input
|
65
60
|
end
|
66
61
|
|
67
|
-
|
68
|
-
|
69
|
-
|
62
|
+
describe 'when dumped and loaded again' do
|
63
|
+
before :all do
|
64
|
+
@resource.save.should be_true
|
65
|
+
@resource.reload
|
66
|
+
end
|
70
67
|
|
71
|
-
|
72
|
-
|
73
|
-
|
68
|
+
it 'includes "fire" in interests' do
|
69
|
+
@resource.interests.should include('fire')
|
70
|
+
end
|
74
71
|
|
75
|
-
|
76
|
-
|
77
|
-
|
72
|
+
it 'includes "water" in interests' do
|
73
|
+
@resource.interests.should include('water')
|
74
|
+
end
|
78
75
|
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
it 'includes "a whole lot of other interesting things" in interests' do
|
77
|
+
@resource.interests.should include('a whole lot of other interesting things')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'has blank entries removed' do
|
81
|
+
@resource.interests.any? { |i| i.blank? }.should be_false
|
82
|
+
end
|
82
83
|
|
83
|
-
|
84
|
-
|
84
|
+
it 'has duplicates removed' do
|
85
|
+
@resource.interests.select { |i| i == 'fire' }.size.should == 1
|
86
|
+
end
|
85
87
|
end
|
86
88
|
end
|
87
89
|
end
|