dm-types 0.10.2 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/dm-types/csv.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
1
3
|
if RUBY_VERSION >= '1.9.0'
|
2
4
|
require 'csv'
|
3
5
|
else
|
@@ -6,27 +8,25 @@ else
|
|
6
8
|
end
|
7
9
|
|
8
10
|
module DataMapper
|
9
|
-
|
10
|
-
class Csv <
|
11
|
-
|
12
|
-
|
13
|
-
def self.load(value, property)
|
11
|
+
class Property
|
12
|
+
class Csv < Text
|
13
|
+
def load(value)
|
14
14
|
case value
|
15
|
-
when String then CSV.parse(value)
|
16
|
-
when Array then value
|
15
|
+
when ::String then CSV.parse(value)
|
16
|
+
when ::Array then value
|
17
17
|
else
|
18
18
|
nil
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def dump(value)
|
23
23
|
case value
|
24
|
-
when Array then CSV.generate { |csv| value.each { |row| csv << row } }
|
25
|
-
when String then value
|
24
|
+
when ::Array then CSV.generate { |csv| value.each { |row| csv << row } }
|
25
|
+
when ::String then value
|
26
26
|
else
|
27
27
|
nil
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end # class Csv
|
31
|
-
end #
|
31
|
+
end # class Property
|
32
32
|
end # module DataMapper
|
data/lib/dm-types/enum.rb
CHANGED
@@ -1,73 +1,56 @@
|
|
1
|
-
|
2
|
-
module Types
|
3
|
-
class Enum < Type
|
4
|
-
primitive Integer
|
1
|
+
require 'dm-core'
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module DataMapper
|
4
|
+
class Property
|
5
|
+
class Enum < Integer
|
6
|
+
accept_options :flags
|
9
7
|
|
10
|
-
|
11
|
-
@flag_map
|
12
|
-
end
|
8
|
+
attr_reader :flag_map
|
13
9
|
|
14
|
-
def
|
15
|
-
|
16
|
-
end
|
10
|
+
def initialize(model, name, options = {}, type = nil)
|
11
|
+
super
|
17
12
|
|
18
|
-
|
19
|
-
enum = Class.new(Enum)
|
20
|
-
enum.flag_map = {}
|
13
|
+
@flag_map = {}
|
21
14
|
|
15
|
+
flags = options.fetch(:flags)
|
22
16
|
flags.each_with_index do |flag, i|
|
23
|
-
|
17
|
+
@flag_map[i + 1] = flag
|
24
18
|
end
|
25
19
|
|
26
|
-
|
20
|
+
if defined?(::DataMapper::Validations)
|
21
|
+
unless model.skip_auto_validation_for?(self)
|
22
|
+
if self.class.ancestors.include?(Property::Enum)
|
23
|
+
allowed = flag_map.values_at(*flag_map.keys.sort)
|
24
|
+
model.validates_within name, model.options_with_message({ :set => allowed }, self, :within)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
-
|
30
|
+
def custom?
|
31
|
+
true
|
31
32
|
end
|
32
33
|
|
33
|
-
def
|
34
|
-
|
34
|
+
def load(value)
|
35
|
+
flag_map[value]
|
35
36
|
end
|
36
37
|
|
37
|
-
def
|
38
|
+
def dump(value)
|
38
39
|
case value
|
39
|
-
|
40
|
-
|
40
|
+
when ::Array then value.collect { |v| dump(v) }
|
41
|
+
else flag_map.invert[value]
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
|
-
def
|
45
|
+
def typecast_to_primitive(value)
|
45
46
|
# Attempt to typecast using the class of the first item in the map.
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
else value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.bind(property)
|
56
|
-
if defined?(::DataMapper::Validate)
|
57
|
-
model = property.model
|
58
|
-
|
59
|
-
unless model.skip_auto_validation_for?(property)
|
60
|
-
if property.type.ancestors.include?(Types::Enum)
|
61
|
-
model.class_eval do
|
62
|
-
flag_map = property.type.flag_map
|
63
|
-
allowed = flag_map.values_at(*flag_map.keys.sort)
|
64
|
-
|
65
|
-
validates_within property.name, options_with_message({ :set => allowed }, property, :within)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
47
|
+
case flag_map[1]
|
48
|
+
when ::Symbol then value.to_sym
|
49
|
+
when ::String then value.to_s
|
50
|
+
when ::Fixnum then value.to_i
|
51
|
+
else value
|
69
52
|
end
|
70
53
|
end
|
71
54
|
end # class Enum
|
72
|
-
end #
|
55
|
+
end # class Property
|
73
56
|
end # module DataMapper
|
data/lib/dm-types/epoch_time.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
|
2
|
-
module Types
|
3
|
-
class EpochTime < DataMapper::Type
|
4
|
-
primitive Integer
|
1
|
+
require 'dm-core'
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module DataMapper
|
4
|
+
class Property
|
5
|
+
class EpochTime < Integer
|
6
|
+
def load(value)
|
7
|
+
if value.kind_of?(::Integer)
|
8
|
+
::Time.at(value)
|
9
9
|
else
|
10
10
|
value
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def dump(value)
|
15
15
|
case value
|
16
|
-
when Integer, Time then value.to_i
|
17
|
-
when DateTime then value.to_time.to_i
|
16
|
+
when ::Integer, ::Time then value.to_i
|
17
|
+
when ::DateTime then value.to_time.to_i
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end # class EpochTime
|
21
|
-
end #
|
21
|
+
end # class Property
|
22
22
|
end # module DataMapper
|
data/lib/dm-types/file_path.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'pathname'
|
2
|
+
require 'dm-core'
|
2
3
|
|
3
4
|
module DataMapper
|
4
|
-
|
5
|
-
class FilePath <
|
6
|
-
|
7
|
-
length 255
|
5
|
+
class Property
|
6
|
+
class FilePath < String
|
7
|
+
length 255
|
8
8
|
|
9
|
-
def
|
9
|
+
def primitive?(value)
|
10
|
+
value.kind_of?(Pathname)
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(value)
|
10
14
|
if value.blank?
|
11
15
|
nil
|
12
16
|
else
|
@@ -14,15 +18,14 @@ module DataMapper
|
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
17
|
-
def
|
21
|
+
def dump(value)
|
18
22
|
return nil if value.blank?
|
19
23
|
value.to_s
|
20
24
|
end
|
21
25
|
|
22
|
-
def
|
23
|
-
|
24
|
-
value.kind_of?(Pathname) ? value : load(value, property)
|
26
|
+
def typecast_to_primitive(value)
|
27
|
+
load(value)
|
25
28
|
end
|
26
29
|
end # class FilePath
|
27
|
-
end #
|
30
|
+
end # class Property
|
28
31
|
end # module DataMapper
|
data/lib/dm-types/flag.rb
CHANGED
@@ -1,36 +1,28 @@
|
|
1
|
-
|
2
|
-
module Types
|
3
|
-
class Flag < Type
|
4
|
-
primitive Integer
|
1
|
+
require 'dm-core'
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module DataMapper
|
4
|
+
class Property
|
5
|
+
class Flag < Integer
|
6
|
+
accept_options :flags
|
9
7
|
|
10
|
-
|
11
|
-
@flag_map
|
12
|
-
end
|
8
|
+
attr_reader :flag_map
|
13
9
|
|
14
|
-
def
|
15
|
-
|
16
|
-
end
|
10
|
+
def initialize(model, name, options = {}, type = nil)
|
11
|
+
super
|
17
12
|
|
18
|
-
|
19
|
-
type = Class.new(Flag)
|
20
|
-
type.flag_map = {}
|
13
|
+
@flag_map = {}
|
21
14
|
|
15
|
+
flags = options.fetch(:flags)
|
22
16
|
flags.each_with_index do |flag, i|
|
23
|
-
|
17
|
+
flag_map[i] = flag
|
24
18
|
end
|
25
|
-
|
26
|
-
type
|
27
19
|
end
|
28
20
|
|
29
|
-
def
|
30
|
-
|
21
|
+
def custom?
|
22
|
+
true
|
31
23
|
end
|
32
24
|
|
33
|
-
def
|
25
|
+
def load(value)
|
34
26
|
return [] if value.nil? || value <= 0
|
35
27
|
|
36
28
|
begin
|
@@ -46,13 +38,13 @@ module DataMapper
|
|
46
38
|
end
|
47
39
|
end
|
48
40
|
|
49
|
-
def
|
41
|
+
def dump(value)
|
50
42
|
return if value.nil?
|
51
43
|
flags = Array(value).map { |flag| flag.to_sym }.flatten
|
52
44
|
flag_map.invert.values_at(*flags).compact.inject(0) { |sum, i| sum += 1 << i }
|
53
45
|
end
|
54
46
|
|
55
|
-
def
|
47
|
+
def typecast(value)
|
56
48
|
case value
|
57
49
|
when nil then nil
|
58
50
|
when Array then value.map {|v| v.to_sym}
|
@@ -60,5 +52,5 @@ module DataMapper
|
|
60
52
|
end
|
61
53
|
end
|
62
54
|
end # class Flag
|
63
|
-
end #
|
55
|
+
end # class Property
|
64
56
|
end # module DataMapper
|
data/lib/dm-types/ip_address.rb
CHANGED
@@ -1,31 +1,35 @@
|
|
1
1
|
require 'ipaddr'
|
2
|
+
require 'dm-core'
|
2
3
|
|
3
4
|
module DataMapper
|
4
|
-
|
5
|
-
class IPAddress <
|
6
|
-
|
7
|
-
length 16
|
5
|
+
class Property
|
6
|
+
class IPAddress < String
|
7
|
+
length 39
|
8
8
|
|
9
|
-
def
|
9
|
+
def primitive?(value)
|
10
|
+
value.kind_of?(IPAddr)
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(value)
|
10
14
|
if value.nil?
|
11
15
|
nil
|
12
|
-
elsif value.is_a?(String) && !value.empty?
|
16
|
+
elsif value.is_a?(::String) && !value.empty?
|
13
17
|
IPAddr.new(value)
|
14
|
-
elsif value.is_a?(String) && value.empty?
|
18
|
+
elsif value.is_a?(::String) && value.empty?
|
15
19
|
IPAddr.new("0.0.0.0")
|
16
20
|
else
|
17
21
|
raise ArgumentError.new("+value+ must be nil or a String")
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
|
-
def
|
25
|
+
def dump(value)
|
22
26
|
return nil if value.nil?
|
23
27
|
value.to_s
|
24
28
|
end
|
25
29
|
|
26
|
-
def
|
27
|
-
|
30
|
+
def typecast_to_primitive(value)
|
31
|
+
load(value)
|
28
32
|
end
|
29
33
|
end # class IPAddress
|
30
|
-
end # module
|
34
|
+
end # module Property
|
31
35
|
end # module DataMapper
|
data/lib/dm-types/json.rb
CHANGED
@@ -1,36 +1,39 @@
|
|
1
|
+
require 'dm-core'
|
1
2
|
require 'json'
|
2
3
|
|
3
4
|
module DataMapper
|
4
|
-
|
5
|
-
class Json <
|
6
|
-
|
5
|
+
class Property
|
6
|
+
class Json < Text
|
7
|
+
def custom?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def primitive?(value)
|
12
|
+
value.kind_of?(::Array) || value.kind_of?(::Hash)
|
13
|
+
end
|
7
14
|
|
8
|
-
def
|
15
|
+
def load(value)
|
9
16
|
if value.nil?
|
10
17
|
nil
|
11
|
-
elsif value.is_a?(String)
|
18
|
+
elsif value.is_a?(::String)
|
12
19
|
::JSON.load(value)
|
13
20
|
else
|
14
21
|
raise ArgumentError.new("+value+ of a property of JSON type must be nil or a String")
|
15
22
|
end
|
16
23
|
end
|
17
24
|
|
18
|
-
def
|
19
|
-
if value.nil? || value.is_a?(String)
|
25
|
+
def dump(value)
|
26
|
+
if value.nil? || value.is_a?(::String)
|
20
27
|
value
|
21
28
|
else
|
22
29
|
::JSON.dump(value)
|
23
30
|
end
|
24
31
|
end
|
25
32
|
|
26
|
-
def
|
27
|
-
|
28
|
-
value
|
29
|
-
else
|
30
|
-
::JSON.load(value.to_s)
|
31
|
-
end
|
33
|
+
def typecast_to_primitive(value)
|
34
|
+
::JSON.load(value.to_s)
|
32
35
|
end
|
33
36
|
end # class Json
|
34
37
|
JSON = Json
|
35
|
-
end #
|
38
|
+
end # class Property
|
36
39
|
end # module DataMapper
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Types
|
3
|
+
module Paranoid
|
4
|
+
module Base
|
5
|
+
def self.included(model)
|
6
|
+
model.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
def paranoid_destroy
|
10
|
+
model.paranoid_properties.each do |name, block|
|
11
|
+
attribute_set(name, block.call(self))
|
12
|
+
end
|
13
|
+
save_self
|
14
|
+
self.persisted_state = Resource::State::Immutable.new(self)
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
def _destroy(execute_hooks = true)
|
22
|
+
return false unless saved?
|
23
|
+
if execute_hooks
|
24
|
+
paranoid_destroy
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end # module Base
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
def with_deleted
|
33
|
+
with_exclusive_scope({}) { block_given? ? yield : all }
|
34
|
+
end
|
35
|
+
end # module ClassMethods
|
36
|
+
end # module Paranoid
|
37
|
+
end # module Types
|
38
|
+
end # module DataMapper
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'dm-types/paranoid/base'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
class Property
|
5
|
+
class ParanoidBoolean < Boolean
|
6
|
+
default false
|
7
|
+
lazy true
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
def bind
|
11
|
+
property_name = name.inspect
|
12
|
+
|
13
|
+
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
14
|
+
include Paranoid::Base
|
15
|
+
|
16
|
+
set_paranoid_property(#{property_name}) { true }
|
17
|
+
|
18
|
+
default_scope(#{repository_name.inspect}).update(#{property_name} => false)
|
19
|
+
RUBY
|
20
|
+
end
|
21
|
+
end # class ParanoidBoolean
|
22
|
+
end # module Property
|
23
|
+
end # module DataMapper
|