ardm-types 1.2.2

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.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +51 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +3 -0
  7. data/Rakefile +4 -0
  8. data/ardm-types.gemspec +29 -0
  9. data/lib/ardm-types.rb +1 -0
  10. data/lib/dm-types/api_key.rb +30 -0
  11. data/lib/dm-types/bcrypt_hash.rb +34 -0
  12. data/lib/dm-types/comma_separated_list.rb +29 -0
  13. data/lib/dm-types/csv.rb +38 -0
  14. data/lib/dm-types/enum.rb +51 -0
  15. data/lib/dm-types/epoch_time.rb +41 -0
  16. data/lib/dm-types/file_path.rb +32 -0
  17. data/lib/dm-types/flag.rb +63 -0
  18. data/lib/dm-types/ip_address.rb +42 -0
  19. data/lib/dm-types/json.rb +50 -0
  20. data/lib/dm-types/paranoid/base.rb +55 -0
  21. data/lib/dm-types/paranoid_boolean.rb +23 -0
  22. data/lib/dm-types/paranoid_datetime.rb +22 -0
  23. data/lib/dm-types/regexp.rb +21 -0
  24. data/lib/dm-types/slug.rb +29 -0
  25. data/lib/dm-types/support/dirty_minder.rb +166 -0
  26. data/lib/dm-types/support/flags.rb +41 -0
  27. data/lib/dm-types/uri.rb +38 -0
  28. data/lib/dm-types/uuid.rb +74 -0
  29. data/lib/dm-types/version.rb +5 -0
  30. data/lib/dm-types/yaml.rb +41 -0
  31. data/lib/dm-types.rb +23 -0
  32. data/spec/fixtures/api_user.rb +14 -0
  33. data/spec/fixtures/article.rb +35 -0
  34. data/spec/fixtures/bookmark.rb +23 -0
  35. data/spec/fixtures/invention.rb +7 -0
  36. data/spec/fixtures/network_node.rb +36 -0
  37. data/spec/fixtures/person.rb +25 -0
  38. data/spec/fixtures/software_package.rb +33 -0
  39. data/spec/fixtures/ticket.rb +21 -0
  40. data/spec/fixtures/tshirt.rb +24 -0
  41. data/spec/integration/api_key_spec.rb +27 -0
  42. data/spec/integration/bcrypt_hash_spec.rb +47 -0
  43. data/spec/integration/comma_separated_list_spec.rb +87 -0
  44. data/spec/integration/dirty_minder_spec.rb +197 -0
  45. data/spec/integration/enum_spec.rb +80 -0
  46. data/spec/integration/epoch_time_spec.rb +61 -0
  47. data/spec/integration/file_path_spec.rb +160 -0
  48. data/spec/integration/flag_spec.rb +72 -0
  49. data/spec/integration/ip_address_spec.rb +153 -0
  50. data/spec/integration/json_spec.rb +72 -0
  51. data/spec/integration/slug_spec.rb +67 -0
  52. data/spec/integration/uri_spec.rb +139 -0
  53. data/spec/integration/uuid_spec.rb +102 -0
  54. data/spec/integration/yaml_spec.rb +69 -0
  55. data/spec/rcov.opts +6 -0
  56. data/spec/shared/flags_shared_spec.rb +37 -0
  57. data/spec/shared/identity_function_group.rb +5 -0
  58. data/spec/spec.opts +4 -0
  59. data/spec/spec_helper.rb +30 -0
  60. data/spec/unit/bcrypt_hash_spec.rb +155 -0
  61. data/spec/unit/csv_spec.rb +142 -0
  62. data/spec/unit/enum_spec.rb +126 -0
  63. data/spec/unit/epoch_time_spec.rb +74 -0
  64. data/spec/unit/file_path_spec.rb +87 -0
  65. data/spec/unit/flag_spec.rb +114 -0
  66. data/spec/unit/ip_address_spec.rb +121 -0
  67. data/spec/unit/json_spec.rb +144 -0
  68. data/spec/unit/paranoid_boolean_spec.rb +150 -0
  69. data/spec/unit/paranoid_datetime_spec.rb +154 -0
  70. data/spec/unit/regexp_spec.rb +63 -0
  71. data/spec/unit/uri_spec.rb +64 -0
  72. data/spec/unit/uuid_spec.rb +25 -0
  73. data/spec/unit/yaml_spec.rb +111 -0
  74. data/tasks/spec.rake +38 -0
  75. data/tasks/yard.rake +9 -0
  76. data/tasks/yardstick.rake +19 -0
  77. metadata +236 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 64d3d24b7d203fef1dd08c5c63fb97af6e7ffbdd
4
+ data.tar.gz: 2ce41762914595258f160111247c308b1f32fe99
5
+ SHA512:
6
+ metadata.gz: e95ea2e08793070c9def64cb04d5cbaa88cfc84ca42c3cff11a25ee05dd1453e74210b1c30fc39a6f747a5a410e721bb84c610e9a74d0ee54be8f758726e0ab0
7
+ data.tar.gz: 58809ba9545ede43fce6982293d049bc1270cb015d796a4a75683870843b34b0ad3880576033b8c1f1165c0749bfe647ba6aebadd4c3df365728b9607026b4aa
data/.gitignore ADDED
@@ -0,0 +1,36 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+ ._*
4
+
5
+ ## TEXTMATE
6
+ *.tmproj
7
+ tmtags
8
+
9
+ ## EMACS
10
+ *~
11
+ \#*
12
+ .\#*
13
+
14
+ ## VIM
15
+ *.swp
16
+
17
+ ## Rubinius
18
+ *.rbc
19
+
20
+ ## PROJECT::GENERAL
21
+ *.gem
22
+ coverage
23
+ rdoc
24
+ pkg
25
+ tmp
26
+ doc
27
+ log
28
+ .yardoc
29
+ measurements
30
+
31
+ ## BUNDLER
32
+ .bundle
33
+ Gemfile.*
34
+
35
+ ## PROJECT::SPECIFIC
36
+ spec/db/
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.5
7
+ - 2.2.0
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: 2.1.5
11
+ - rvm: 2.2.0
data/Gemfile ADDED
@@ -0,0 +1,51 @@
1
+ require 'pathname'
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ SOURCE = ENV.fetch('SOURCE', :git).to_sym
8
+ REPO_POSTFIX = SOURCE == :path ? '' : '.git'
9
+ DATAMAPPER = SOURCE == :path ? Pathname(__FILE__).dirname.parent : 'http://github.com/ar-dm'
10
+ DM_VERSION = '~> 1.2.0'
11
+ DO_VERSION = '~> 0.10.6'
12
+ DM_DO_ADAPTERS = %w[ sqlite postgres mysql oracle sqlserver ]
13
+ CURRENT_BRANCH = ENV.fetch('GIT_BRANCH', 'master')
14
+
15
+ gem 'ardm-core', DM_VERSION, SOURCE => "#{DATAMAPPER}/ardm-core#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
16
+
17
+ group :development do
18
+ gem 'ardm-validations', DM_VERSION, SOURCE => "#{DATAMAPPER}/ardm-validations#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
19
+ end
20
+
21
+ group :datamapper do
22
+
23
+ adapters = ENV['ADAPTER'] || ENV['ADAPTERS']
24
+ adapters = adapters.to_s.tr(',', ' ').split.uniq - %w[ in_memory ]
25
+
26
+ if (do_adapters = DM_DO_ADAPTERS & adapters).any?
27
+ do_options = {}
28
+ do_options[:git] = "#{DATAMAPPER}/do#{REPO_POSTFIX}" if ENV['DO_GIT'] == 'true'
29
+
30
+ gem 'data_objects', DO_VERSION, do_options.dup
31
+
32
+ do_adapters.each do |adapter|
33
+ adapter = 'sqlite3' if adapter == 'sqlite'
34
+ gem "do_#{adapter}", DO_VERSION, do_options.dup
35
+ end
36
+
37
+ gem 'ardm-do-adapter', DM_VERSION, SOURCE => "#{DATAMAPPER}/ardm-do-adapter#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
38
+ end
39
+
40
+ adapters.each do |adapter|
41
+ gem "ardm-#{adapter}-adapter", DM_VERSION, SOURCE => "#{DATAMAPPER}/ardm-#{adapter}-adapter#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
42
+ end
43
+
44
+ plugins = ENV['PLUGINS'] || ENV['PLUGIN']
45
+ plugins = plugins.to_s.tr(',', ' ').split.push('ardm-migrations').uniq
46
+
47
+ plugins.each do |plugin|
48
+ gem plugin, DM_VERSION, SOURCE => "#{DATAMAPPER}/#{plugin}#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
49
+ end
50
+
51
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Sam Smoot, Dan Kubb
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.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = dm-types
2
+
3
+ DataMapper plugin providing many extra types for use in data models.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ FileList['tasks/**/*.rake'].each { |task| import task }
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/dm-types/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "ardm-types"
6
+ gem.version = DataMapper::Types::VERSION
7
+
8
+ gem.authors = [ 'Martin Emde', 'Dan Kubb' ]
9
+ gem.email = [ 'me@martinemde.com', "dan.kubb@gmail.com" ]
10
+ gem.summary = "Ardm fork of dm-types"
11
+ gem.description = gem.summary
12
+ gem.homepage = "http://github.com/martinemde/ardm-types"
13
+ gem.license = "MIT"
14
+
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- {spec}/*`.split("\n")
17
+ gem.extra_rdoc_files = %w[LICENSE README.rdoc]
18
+ gem.require_paths = [ "lib" ]
19
+
20
+ gem.add_runtime_dependency 'ardm-core', '~> 1.2'
21
+ gem.add_runtime_dependency 'bcrypt', '~> 3.0'
22
+ gem.add_runtime_dependency 'fastercsv', '~> 1.5'
23
+ gem.add_runtime_dependency 'multi_json', '~> 1.0'
24
+ gem.add_runtime_dependency 'stringex', '~> 1.3'
25
+ gem.add_runtime_dependency 'uuidtools', '~> 2.1'
26
+
27
+ gem.add_development_dependency 'rake', '~> 0.9'
28
+ gem.add_development_dependency 'rspec', '~> 1.3'
29
+ end
data/lib/ardm-types.rb ADDED
@@ -0,0 +1 @@
1
+ require 'dm-types'
@@ -0,0 +1,30 @@
1
+ require 'dm-core'
2
+
3
+ require 'digest/sha1'
4
+
5
+ module DataMapper
6
+ class Property
7
+ class APIKey < String
8
+
9
+ # The amount of random seed data to use to generate tha API Key
10
+ PADDING = 256
11
+
12
+ length 40
13
+ unique true
14
+ default proc { APIKey.generate }
15
+
16
+ #
17
+ # Generates a new API Key.
18
+ #
19
+ # @return [String]
20
+ # The new API Key.
21
+ #
22
+ def self.generate
23
+ sha1 = Digest::SHA1.new
24
+
25
+ PADDING.times { sha1 << rand(256).chr }
26
+ return sha1.hexdigest
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ require 'dm-core'
2
+ require 'bcrypt'
3
+
4
+ module DataMapper
5
+ class Property
6
+ class BCryptHash < String
7
+
8
+ length 60
9
+
10
+ def primitive?(value)
11
+ value.kind_of?(BCrypt::Password)
12
+ end
13
+
14
+ def load(value)
15
+ unless value.nil?
16
+ begin
17
+ primitive?(value) ? value : BCrypt::Password.new(value)
18
+ rescue BCrypt::Errors::InvalidHash
19
+ BCrypt::Password.create(value, :cost => BCrypt::Engine::DEFAULT_COST)
20
+ end
21
+ end
22
+ end
23
+
24
+ def dump(value)
25
+ load(value)
26
+ end
27
+
28
+ def typecast_to_primitive(value)
29
+ load(value)
30
+ end
31
+
32
+ end # class BCryptHash
33
+ end # class Property
34
+ end # module DataMapper
@@ -0,0 +1,29 @@
1
+ require 'dm-core'
2
+ require 'dm-types/yaml'
3
+
4
+ module DataMapper
5
+ class Property
6
+ class CommaSeparatedList < Yaml
7
+
8
+ def dump(value)
9
+ if value.nil?
10
+ nil
11
+ elsif value.kind_of?(::Array)
12
+ super(value)
13
+ elsif value.kind_of?(::String)
14
+ v = []
15
+
16
+ value.split(',').each do |element|
17
+ element.strip!
18
+ v << element unless element.empty?
19
+ end
20
+
21
+ super(v)
22
+ else
23
+ raise ArgumentError, "+value+ of CommaSeparatedList must be a string, an array or nil, but given #{value.inspect}"
24
+ end
25
+ end # dump
26
+
27
+ end # CommaSeparatedList
28
+ end # Property
29
+ end # DataMapper
@@ -0,0 +1,38 @@
1
+ require 'dm-core'
2
+ require 'dm-types/support/dirty_minder'
3
+
4
+ if RUBY_VERSION >= '1.9.0'
5
+ require 'csv'
6
+ else
7
+ require 'fastercsv' # must be ~>1.5
8
+ CSV = FasterCSV unless defined?(CSV)
9
+ end
10
+
11
+ module DataMapper
12
+ class Property
13
+ class Csv < Text
14
+
15
+ def primitive?(value)
16
+ super || value.kind_of?(::Array)
17
+ end
18
+
19
+ def load(value)
20
+ case value
21
+ when ::String then CSV.parse(value)
22
+ when ::Array then value
23
+ end
24
+ end
25
+
26
+ def dump(value)
27
+ case value
28
+ when ::Array
29
+ CSV.generate { |csv| value.each { |row| csv << row } }
30
+ when ::String then value
31
+ end
32
+ end
33
+
34
+ include ::DataMapper::Property::DirtyMinder
35
+
36
+ end # class Csv
37
+ end # class Property
38
+ end # module DataMapper
@@ -0,0 +1,51 @@
1
+ require 'dm-core'
2
+ require 'dm-types/support/flags'
3
+
4
+ module DataMapper
5
+ class Property
6
+ class Enum < Integer
7
+ min 1
8
+
9
+ include Flags
10
+
11
+ def initialize(model, name, options = {})
12
+ @flag_map = {}
13
+
14
+ flags = options.fetch(:flags, self.class.flags)
15
+ flags.each_with_index do |flag, i|
16
+ @flag_map[i.succ] = flag
17
+ end
18
+
19
+ if self.class.accepted_options.include?(:set) && !options.include?(:set)
20
+ options[:set] = @flag_map.values_at(*@flag_map.keys.sort)
21
+ end
22
+
23
+ options[:max] = @flag_map.size
24
+
25
+ super
26
+ end
27
+
28
+ def load(value)
29
+ flag_map[value]
30
+ end
31
+
32
+ def dump(value)
33
+ case value
34
+ when ::Array then value.collect { |v| dump(v) }
35
+ else flag_map.invert[value]
36
+ end
37
+ end
38
+
39
+ def typecast_to_primitive(value)
40
+ # Attempt to typecast using the class of the first item in the map.
41
+ case flag_map[1]
42
+ when ::Symbol then value.to_sym
43
+ when ::String then value.to_s
44
+ when ::Fixnum then value.to_i
45
+ else value
46
+ end
47
+ end
48
+
49
+ end # class Enum
50
+ end # class Property
51
+ end # module DataMapper
@@ -0,0 +1,41 @@
1
+ require 'dm-core'
2
+
3
+ module DataMapper
4
+ class Property
5
+ class EpochTime < Integer
6
+
7
+ def load(value)
8
+ if value.kind_of?(::Numeric)
9
+ ::Time.at(value.to_i)
10
+ else
11
+ value
12
+ end
13
+ end
14
+
15
+ def dump(value)
16
+ value.to_i if value
17
+ end
18
+
19
+ def custom?
20
+ true
21
+ end
22
+
23
+ def typecast(value)
24
+ case value
25
+ when ::Time then value
26
+ when ::Numeric, /\A\d+\z/ then ::Time.at(value.to_i)
27
+ when ::DateTime then datetime_to_time(value)
28
+ when ::String then ::Time.parse(value)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def datetime_to_time(datetime)
35
+ utc = datetime.new_offset(0)
36
+ ::Time.utc(utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec)
37
+ end
38
+
39
+ end # class EpochTime
40
+ end # class Property
41
+ end # module DataMapper
@@ -0,0 +1,32 @@
1
+ require 'pathname'
2
+ require 'dm-core'
3
+
4
+ module DataMapper
5
+ class Property
6
+ class FilePath < String
7
+
8
+ length 255
9
+
10
+ def primitive?(value)
11
+ value.kind_of?(Pathname)
12
+ end
13
+
14
+ def valid?(value, negated = false)
15
+ super || dump(value).kind_of?(::String)
16
+ end
17
+
18
+ def load(value)
19
+ Pathname.new(value) unless DataMapper::Ext.blank?(value)
20
+ end
21
+
22
+ def dump(value)
23
+ value.to_s unless DataMapper::Ext.blank?(value)
24
+ end
25
+
26
+ def typecast_to_primitive(value)
27
+ load(value)
28
+ end
29
+
30
+ end # class FilePath
31
+ end # class Property
32
+ end # module DataMapper
@@ -0,0 +1,63 @@
1
+ require 'dm-core'
2
+ require 'dm-types/support/flags'
3
+
4
+ module DataMapper
5
+ class Property
6
+ class Flag < Integer
7
+
8
+ include Flags
9
+
10
+ def initialize(model, name, options = {})
11
+ super
12
+
13
+ @flag_map = {}
14
+
15
+ flags = options.fetch(:flags, self.class.flags)
16
+ flags.each_with_index do |flag, i|
17
+ flag_map[i] = flag
18
+ end
19
+ end
20
+
21
+ def load(value)
22
+ return [] if value.nil? || value <= 0
23
+
24
+ begin
25
+ matches = []
26
+
27
+ 0.upto(flag_map.size - 1) do |i|
28
+ matches << flag_map[i] if value[i] == 1
29
+ end
30
+
31
+ matches.compact
32
+ rescue TypeError, Errno::EDOM
33
+ []
34
+ end
35
+ end
36
+
37
+ def dump(value)
38
+ unless value.nil?
39
+ flags = Array(value).map { |flag| flag.to_sym }
40
+ flags.uniq!
41
+
42
+ flag = 0
43
+
44
+ flag_map.invert.values_at(*flags).each do |i|
45
+ next if i.nil?
46
+ flag += (1 << i)
47
+ end
48
+
49
+ flag
50
+ end
51
+ end
52
+
53
+ def typecast(value)
54
+ case value
55
+ when nil then nil
56
+ when ::Array then value.map { |v| v.to_sym }
57
+ else [value.to_sym]
58
+ end
59
+ end
60
+
61
+ end # class Flag
62
+ end # class Property
63
+ end # module DataMapper
@@ -0,0 +1,42 @@
1
+ require 'ipaddr'
2
+ require 'dm-core'
3
+
4
+ module DataMapper
5
+ class Property
6
+ class IPAddress < String
7
+
8
+ length 39
9
+
10
+ def primitive?(value)
11
+ value.kind_of?(IPAddr)
12
+ end
13
+
14
+ def valid?(value, negated = false)
15
+ super || dump(value).kind_of?(::String)
16
+ end
17
+
18
+ def load(value)
19
+ if value.nil?
20
+ nil
21
+ elsif value.is_a?(::String)
22
+ unless value.empty?
23
+ IPAddr.new(value)
24
+ else
25
+ IPAddr.new("0.0.0.0")
26
+ end
27
+ else
28
+ raise ArgumentError.new("+value+ must be nil or a String")
29
+ end
30
+ end
31
+
32
+ def dump(value)
33
+ value.to_s unless value.nil?
34
+ end
35
+
36
+ def typecast_to_primitive(value)
37
+ load(value)
38
+ end
39
+
40
+ end # class IPAddress
41
+ end # module Property
42
+ end # module DataMapper
@@ -0,0 +1,50 @@
1
+ require 'dm-core'
2
+ require 'dm-types/support/dirty_minder'
3
+ require 'multi_json'
4
+
5
+ module DataMapper
6
+ class Property
7
+ class Json < Text
8
+
9
+ def custom?
10
+ true
11
+ end
12
+
13
+ def primitive?(value)
14
+ value.kind_of?(::Array) || value.kind_of?(::Hash)
15
+ end
16
+
17
+ def valid?(value, negated = false)
18
+ super || dump(value).kind_of?(::String)
19
+ end
20
+
21
+ def load(value)
22
+ if value.nil?
23
+ nil
24
+ elsif value.is_a?(::String)
25
+ typecast_to_primitive(value)
26
+ else
27
+ raise ArgumentError.new("+value+ of a property of JSON type must be nil or a String")
28
+ end
29
+ end
30
+
31
+ def dump(value)
32
+ if value.nil? || value.is_a?(::String)
33
+ value
34
+ else
35
+ MultiJson.encode(value)
36
+ end
37
+ end
38
+
39
+ def typecast_to_primitive(value)
40
+ MultiJson.decode(value.to_s)
41
+ end
42
+
43
+ include ::DataMapper::Property::DirtyMinder
44
+
45
+ end # class Json
46
+
47
+ JSON = Json
48
+
49
+ end # class Property
50
+ end # module DataMapper
@@ -0,0 +1,55 @@
1
+ module DataMapper
2
+ module Types
3
+ module Paranoid
4
+ module Base
5
+ def self.included(model)
6
+ model.extend ClassMethods
7
+ model.instance_variable_set(:@paranoid_properties, {})
8
+ end
9
+
10
+ def paranoid_destroy
11
+ model.paranoid_properties.each do |name, block|
12
+ attribute_set(name, block.call(self))
13
+ end
14
+ save_self
15
+ self.persistence_state = Resource::PersistenceState::Immutable.new(self)
16
+ true
17
+ end
18
+
19
+ private
20
+
21
+ # @api private
22
+ def _destroy(execute_hooks = true)
23
+ return false unless saved?
24
+ if execute_hooks
25
+ paranoid_destroy
26
+ else
27
+ super
28
+ end
29
+ end
30
+ end # module Base
31
+
32
+ module ClassMethods
33
+ def inherited(model)
34
+ model.instance_variable_set(:@paranoid_properties, @paranoid_properties.dup)
35
+ super
36
+ end
37
+
38
+ # @api public
39
+ def with_deleted
40
+ with_exclusive_scope({}) { block_given? ? yield : all }
41
+ end
42
+
43
+ # @api private
44
+ def paranoid_properties
45
+ @paranoid_properties
46
+ end
47
+
48
+ # @api private
49
+ def set_paranoid_property(name, &block)
50
+ paranoid_properties[name] = block
51
+ end
52
+ end # module ClassMethods
53
+ end # module Paranoid
54
+ end # module Types
55
+ 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 DataMapper::Types::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
@@ -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 DataMapper::Types::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