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.
Files changed (58) hide show
  1. data/.gitignore +36 -0
  2. data/Gemfile +147 -0
  3. data/Rakefile +7 -8
  4. data/VERSION +1 -1
  5. data/dm-types.gemspec +61 -20
  6. data/lib/dm-types.rb +24 -19
  7. data/lib/dm-types/bcrypt_hash.rb +17 -13
  8. data/lib/dm-types/comma_separated_list.rb +11 -16
  9. data/lib/dm-types/csv.rb +11 -11
  10. data/lib/dm-types/enum.rb +33 -50
  11. data/lib/dm-types/epoch_time.rb +11 -11
  12. data/lib/dm-types/file_path.rb +13 -10
  13. data/lib/dm-types/flag.rb +17 -25
  14. data/lib/dm-types/ip_address.rb +15 -11
  15. data/lib/dm-types/json.rb +17 -14
  16. data/lib/dm-types/paranoid/base.rb +38 -0
  17. data/lib/dm-types/paranoid_boolean.rb +23 -0
  18. data/lib/dm-types/paranoid_datetime.rb +22 -0
  19. data/lib/dm-types/regexp.rb +8 -8
  20. data/lib/dm-types/slug.rb +7 -12
  21. data/lib/dm-types/uri.rb +21 -9
  22. data/lib/dm-types/uuid.rb +18 -11
  23. data/lib/dm-types/yaml.rb +12 -10
  24. data/spec/fixtures/article.rb +0 -2
  25. data/spec/fixtures/bookmark.rb +0 -2
  26. data/spec/fixtures/network_node.rb +0 -2
  27. data/spec/fixtures/person.rb +0 -2
  28. data/spec/fixtures/software_package.rb +0 -2
  29. data/spec/fixtures/ticket.rb +2 -4
  30. data/spec/fixtures/tshirt.rb +3 -5
  31. data/spec/integration/bcrypt_hash_spec.rb +33 -31
  32. data/spec/integration/comma_separated_list_spec.rb +55 -53
  33. data/spec/integration/enum_spec.rb +55 -53
  34. data/spec/integration/file_path_spec.rb +105 -103
  35. data/spec/integration/flag_spec.rb +42 -40
  36. data/spec/integration/ip_address_spec.rb +91 -89
  37. data/spec/integration/json_spec.rb +41 -39
  38. data/spec/integration/slug_spec.rb +36 -34
  39. data/spec/integration/uri_spec.rb +82 -79
  40. data/spec/integration/uuid_spec.rb +63 -61
  41. data/spec/integration/yaml_spec.rb +37 -35
  42. data/spec/spec_helper.rb +7 -36
  43. data/spec/unit/bcrypt_hash_spec.rb +18 -10
  44. data/spec/unit/csv_spec.rb +92 -80
  45. data/spec/unit/enum_spec.rb +27 -42
  46. data/spec/unit/epoch_time_spec.rb +18 -7
  47. data/spec/unit/file_path_spec.rb +15 -10
  48. data/spec/unit/flag_spec.rb +13 -36
  49. data/spec/unit/ip_address_spec.rb +13 -10
  50. data/spec/unit/json_spec.rb +21 -14
  51. data/spec/unit/paranoid_boolean_spec.rb +138 -0
  52. data/spec/unit/paranoid_datetime_spec.rb +143 -0
  53. data/spec/unit/regexp_spec.rb +15 -5
  54. data/spec/unit/uri_spec.rb +13 -9
  55. data/spec/unit/yaml_spec.rb +16 -9
  56. data/tasks/local_gemfile.rake +18 -0
  57. data/tasks/spec.rake +0 -3
  58. metadata +122 -52
@@ -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
- module Types
10
- class Csv < DataMapper::Type
11
- primitive Text
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 self.dump(value, property)
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 # module Types
31
+ end # class Property
32
32
  end # module DataMapper
@@ -1,73 +1,56 @@
1
- module DataMapper
2
- module Types
3
- class Enum < Type
4
- primitive Integer
1
+ require 'dm-core'
5
2
 
6
- def self.inherited(target)
7
- target.instance_variable_set("@primitive", self.primitive)
8
- end
3
+ module DataMapper
4
+ class Property
5
+ class Enum < Integer
6
+ accept_options :flags
9
7
 
10
- def self.flag_map
11
- @flag_map
12
- end
8
+ attr_reader :flag_map
13
9
 
14
- def self.flag_map=(value)
15
- @flag_map = value
16
- end
10
+ def initialize(model, name, options = {}, type = nil)
11
+ super
17
12
 
18
- def self.new(*flags)
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
- enum.flag_map[i + 1] = flag
17
+ @flag_map[i + 1] = flag
24
18
  end
25
19
 
26
- enum
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 self.[](*flags)
30
- new(*flags)
30
+ def custom?
31
+ true
31
32
  end
32
33
 
33
- def self.load(value, property)
34
- self.flag_map[value]
34
+ def load(value)
35
+ flag_map[value]
35
36
  end
36
37
 
37
- def self.dump(value, property)
38
+ def dump(value)
38
39
  case value
39
- when Array then value.collect { |v| self.dump(v, property) }
40
- else self.flag_map.invert[value]
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 self.typecast(value, property)
45
+ def typecast_to_primitive(value)
45
46
  # Attempt to typecast using the class of the first item in the map.
46
- return value if value.nil?
47
- case self.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
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 # module Types
55
+ end # class Property
73
56
  end # module DataMapper
@@ -1,22 +1,22 @@
1
- module DataMapper
2
- module Types
3
- class EpochTime < DataMapper::Type
4
- primitive Integer
1
+ require 'dm-core'
5
2
 
6
- def self.load(value, property)
7
- if value.kind_of?(Integer)
8
- Time.at(value)
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 self.dump(value, property)
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 # module Types
21
+ end # class Property
22
22
  end # module DataMapper
@@ -1,12 +1,16 @@
1
1
  require 'pathname'
2
+ require 'dm-core'
2
3
 
3
4
  module DataMapper
4
- module Types
5
- class FilePath < DataMapper::Type
6
- primitive String
7
- length 255
5
+ class Property
6
+ class FilePath < String
7
+ length 255
8
8
 
9
- def self.load(value, property)
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 self.dump(value, property)
21
+ def dump(value)
18
22
  return nil if value.blank?
19
23
  value.to_s
20
24
  end
21
25
 
22
- def self.typecast(value, property)
23
- # Leave alone if a Pathname is given.
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 # module Types
30
+ end # class Property
28
31
  end # module DataMapper
@@ -1,36 +1,28 @@
1
- module DataMapper
2
- module Types
3
- class Flag < Type
4
- primitive Integer
1
+ require 'dm-core'
5
2
 
6
- def self.inherited(target)
7
- target.instance_variable_set('@primitive', self.primitive)
8
- end
3
+ module DataMapper
4
+ class Property
5
+ class Flag < Integer
6
+ accept_options :flags
9
7
 
10
- def self.flag_map
11
- @flag_map
12
- end
8
+ attr_reader :flag_map
13
9
 
14
- def self.flag_map=(value)
15
- @flag_map = value
16
- end
10
+ def initialize(model, name, options = {}, type = nil)
11
+ super
17
12
 
18
- def self.new(*flags)
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
- type.flag_map[i] = flag
17
+ flag_map[i] = flag
24
18
  end
25
-
26
- type
27
19
  end
28
20
 
29
- def self.[](*flags)
30
- new(*flags)
21
+ def custom?
22
+ true
31
23
  end
32
24
 
33
- def self.load(value, property)
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 self.dump(value, property)
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 self.typecast(value, property)
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 # module Types
55
+ end # class Property
64
56
  end # module DataMapper
@@ -1,31 +1,35 @@
1
1
  require 'ipaddr'
2
+ require 'dm-core'
2
3
 
3
4
  module DataMapper
4
- module Types
5
- class IPAddress < DataMapper::Type
6
- primitive String
7
- length 16
5
+ class Property
6
+ class IPAddress < String
7
+ length 39
8
8
 
9
- def self.load(value, property)
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 self.dump(value, property)
25
+ def dump(value)
22
26
  return nil if value.nil?
23
27
  value.to_s
24
28
  end
25
29
 
26
- def self.typecast(value, property)
27
- value.kind_of?(IPAddr) ? value : load(value, property)
30
+ def typecast_to_primitive(value)
31
+ load(value)
28
32
  end
29
33
  end # class IPAddress
30
- end # module Types
34
+ end # module Property
31
35
  end # module DataMapper
@@ -1,36 +1,39 @@
1
+ require 'dm-core'
1
2
  require 'json'
2
3
 
3
4
  module DataMapper
4
- module Types
5
- class Json < DataMapper::Type
6
- primitive Text
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 self.load(value, property)
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 self.dump(value, property)
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 self.typecast(value, property)
27
- if value.nil? || value.kind_of?(Array) || value.kind_of?(Hash)
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 # module Types
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