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.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/.travis.yml +11 -0
- data/Gemfile +51 -0
- data/LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +4 -0
- data/ardm-types.gemspec +29 -0
- data/lib/ardm-types.rb +1 -0
- data/lib/dm-types/api_key.rb +30 -0
- data/lib/dm-types/bcrypt_hash.rb +34 -0
- data/lib/dm-types/comma_separated_list.rb +29 -0
- data/lib/dm-types/csv.rb +38 -0
- data/lib/dm-types/enum.rb +51 -0
- data/lib/dm-types/epoch_time.rb +41 -0
- data/lib/dm-types/file_path.rb +32 -0
- data/lib/dm-types/flag.rb +63 -0
- data/lib/dm-types/ip_address.rb +42 -0
- data/lib/dm-types/json.rb +50 -0
- data/lib/dm-types/paranoid/base.rb +55 -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 +21 -0
- data/lib/dm-types/slug.rb +29 -0
- data/lib/dm-types/support/dirty_minder.rb +166 -0
- data/lib/dm-types/support/flags.rb +41 -0
- data/lib/dm-types/uri.rb +38 -0
- data/lib/dm-types/uuid.rb +74 -0
- data/lib/dm-types/version.rb +5 -0
- data/lib/dm-types/yaml.rb +41 -0
- data/lib/dm-types.rb +23 -0
- data/spec/fixtures/api_user.rb +14 -0
- data/spec/fixtures/article.rb +35 -0
- data/spec/fixtures/bookmark.rb +23 -0
- data/spec/fixtures/invention.rb +7 -0
- data/spec/fixtures/network_node.rb +36 -0
- data/spec/fixtures/person.rb +25 -0
- data/spec/fixtures/software_package.rb +33 -0
- data/spec/fixtures/ticket.rb +21 -0
- data/spec/fixtures/tshirt.rb +24 -0
- data/spec/integration/api_key_spec.rb +27 -0
- data/spec/integration/bcrypt_hash_spec.rb +47 -0
- data/spec/integration/comma_separated_list_spec.rb +87 -0
- data/spec/integration/dirty_minder_spec.rb +197 -0
- data/spec/integration/enum_spec.rb +80 -0
- data/spec/integration/epoch_time_spec.rb +61 -0
- data/spec/integration/file_path_spec.rb +160 -0
- data/spec/integration/flag_spec.rb +72 -0
- data/spec/integration/ip_address_spec.rb +153 -0
- data/spec/integration/json_spec.rb +72 -0
- data/spec/integration/slug_spec.rb +67 -0
- data/spec/integration/uri_spec.rb +139 -0
- data/spec/integration/uuid_spec.rb +102 -0
- data/spec/integration/yaml_spec.rb +69 -0
- data/spec/rcov.opts +6 -0
- data/spec/shared/flags_shared_spec.rb +37 -0
- data/spec/shared/identity_function_group.rb +5 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/unit/bcrypt_hash_spec.rb +155 -0
- data/spec/unit/csv_spec.rb +142 -0
- data/spec/unit/enum_spec.rb +126 -0
- data/spec/unit/epoch_time_spec.rb +74 -0
- data/spec/unit/file_path_spec.rb +87 -0
- data/spec/unit/flag_spec.rb +114 -0
- data/spec/unit/ip_address_spec.rb +121 -0
- data/spec/unit/json_spec.rb +144 -0
- data/spec/unit/paranoid_boolean_spec.rb +150 -0
- data/spec/unit/paranoid_datetime_spec.rb +154 -0
- data/spec/unit/regexp_spec.rb +63 -0
- data/spec/unit/uri_spec.rb +64 -0
- data/spec/unit/uuid_spec.rb +25 -0
- data/spec/unit/yaml_spec.rb +111 -0
- data/tasks/spec.rake +38 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +236 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
class Property
|
5
|
+
class Regexp < String
|
6
|
+
|
7
|
+
def load(value)
|
8
|
+
::Regexp.new(value) unless value.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def dump(value)
|
12
|
+
value.source unless value.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def typecast(value)
|
16
|
+
load(value)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'stringex'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
class Property
|
6
|
+
class Slug < String
|
7
|
+
|
8
|
+
# Maximum length chosen because URI type is limited to 2000
|
9
|
+
# characters, and a slug is a component of a URI, so it should
|
10
|
+
# not exceed the maximum URI length either.
|
11
|
+
length 2000
|
12
|
+
|
13
|
+
def typecast(value)
|
14
|
+
if value.nil?
|
15
|
+
nil
|
16
|
+
elsif value.respond_to?(:to_str)
|
17
|
+
escape(value.to_str)
|
18
|
+
else
|
19
|
+
raise ArgumentError, '+value+ must be nil or respond to #to_str'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def escape(string)
|
24
|
+
string.to_url
|
25
|
+
end
|
26
|
+
|
27
|
+
end # class Slug
|
28
|
+
end # class Property
|
29
|
+
end # module DataMapper
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# Approach
|
2
|
+
#
|
3
|
+
# We need to detect whether or not the underlying Hash or Array changed and
|
4
|
+
# update the dirty-ness of the encapsulating Resource accordingly (so that it
|
5
|
+
# will actually save).
|
6
|
+
#
|
7
|
+
# DM's state-tracking code only triggers dirty-ness by comparing the new value
|
8
|
+
# against the instance's Property's current value. WRT mutation, we have to
|
9
|
+
# choose one of the following approaches:
|
10
|
+
#
|
11
|
+
# (1) mutate a copy ("after"), then invoke the Resource assignment and State
|
12
|
+
# tracking
|
13
|
+
#
|
14
|
+
# (2) create a copy ("before"), mutate self ("after"), then invoke the
|
15
|
+
# Resource assignment and State tracking
|
16
|
+
#
|
17
|
+
# (1) seemed simpler at first, but it required additional steps to alias the
|
18
|
+
# original (pre-hooked) methods before overriding them (so they could be invoked
|
19
|
+
# externally, ala self.clone.send("orig_...")), and more importantly it resulted
|
20
|
+
# in any external references keeping their old value (instead of getting the
|
21
|
+
# new), like so:
|
22
|
+
#
|
23
|
+
# copy = instance.json
|
24
|
+
# copy[:some] = :value
|
25
|
+
# instance.json[:some] == :value
|
26
|
+
# => true
|
27
|
+
# copy[:some] == :value
|
28
|
+
# => false # fk!
|
29
|
+
#
|
30
|
+
# In order to do (2) and still have State tracking trigger normally, we need to
|
31
|
+
# ensure the Property has a different value other than self when the State
|
32
|
+
# tracking does the comparison. This equates to setting the Property directly
|
33
|
+
# to the "before" value (a clone and thus a different object/value) before
|
34
|
+
# invoking the Resource Property/attribute assignment.
|
35
|
+
#
|
36
|
+
# The cloning of any value might sound expensive, but it's identical in cost to
|
37
|
+
# what you already had to do: assign a cloned copy in order to trigger
|
38
|
+
# dirty-ness (e.g. ::DataMapper::Property::Json):
|
39
|
+
#
|
40
|
+
# model.json = model.json.merge({:some=>:value})
|
41
|
+
#
|
42
|
+
# Hooking Core Classes
|
43
|
+
#
|
44
|
+
# We want to hook certain methods on Hash and Array to trigger dirty-ness in the
|
45
|
+
# resource. However, because these are core classes, they are individually
|
46
|
+
# mapped to C primitives and thus cannot be hooked through #send/#__send__. We
|
47
|
+
# have to override each method, but we don't want to write a lot of code.
|
48
|
+
#
|
49
|
+
# Minimally Invasive
|
50
|
+
#
|
51
|
+
# We also want to extend behaviour of existing class instances instead of
|
52
|
+
# impersonating/delegating from a proxy class of our own, or overriding a global
|
53
|
+
# class behaviour. This is the most flexible approach and least prone to error,
|
54
|
+
# since it leaves open the option for consumers to proxy or override global
|
55
|
+
# classes, and is less likely to interfere with method_missing/etc shenanigans.
|
56
|
+
#
|
57
|
+
# Nested Object Mutations
|
58
|
+
#
|
59
|
+
# Since we use {Array,Hash}#hash to compare before & after, and #hash accounts
|
60
|
+
# for/traverses nested structures, no "deep" inspection logic is technically
|
61
|
+
# necessary. However, Resource#dirty? only queries a cache of dirtied
|
62
|
+
# attributes, whose own population strategy is to hook assignment (instead of
|
63
|
+
# interrogating properties on demand). So the approach is still limited to
|
64
|
+
# top-level mutators.
|
65
|
+
#
|
66
|
+
# Maybe consider optional "advisory" Property#dirty? method for Resource#dirty?
|
67
|
+
# that custom properties could use for this purpose.
|
68
|
+
#
|
69
|
+
# TODO: add support for detecting mutations in nested objects, but we can't
|
70
|
+
# catch the assignment from here (yet?).
|
71
|
+
# TODO: ensure we covered all indirectly-mutable classes that DM uses underneath
|
72
|
+
# a property type
|
73
|
+
# TODO: figure out how to hook core class methods on RBX (which do use #send)
|
74
|
+
|
75
|
+
module DataMapper
|
76
|
+
class Property
|
77
|
+
module DirtyMinder
|
78
|
+
|
79
|
+
module Hooker
|
80
|
+
MUTATION_METHODS = {
|
81
|
+
::Array => %w{
|
82
|
+
[]= push << shift pop insert unshift delete
|
83
|
+
delete_at replace fill clear
|
84
|
+
slice! reverse! rotate! compact! flatten! uniq!
|
85
|
+
collect! map! sort! sort_by! reject! delete_if!
|
86
|
+
select! shuffle!
|
87
|
+
}.select { |meth| ::Array.instance_methods.any? { |m| m.to_s == meth } },
|
88
|
+
|
89
|
+
::Hash => %w{
|
90
|
+
[]= store delete delete_if replace update
|
91
|
+
delete rehash shift clear
|
92
|
+
merge! reject! select!
|
93
|
+
}.select { |meth| ::Hash.instance_methods.any? { |m| m.to_s == meth } },
|
94
|
+
}
|
95
|
+
|
96
|
+
def self.extended(instance)
|
97
|
+
# FIXME: DirtyMinder is currently unsupported on RBX, because unlike
|
98
|
+
# the other supported Rubies, RBX core class (e.g. Array, Hash)
|
99
|
+
# methods use #send(). In other words, the other Rubies don't use
|
100
|
+
# #send() (they map directly to their C functions).
|
101
|
+
#
|
102
|
+
# The current methodology takes advantage of this by using #send() to
|
103
|
+
# forward method invocations we've hooked. Supporting RBX will
|
104
|
+
# require finding another way, possibly for all Rubies. In the
|
105
|
+
# meantime, something is better than nothing.
|
106
|
+
return if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'rbx'
|
107
|
+
|
108
|
+
return unless type = MUTATION_METHODS.keys.find { |k| instance.kind_of?(k) }
|
109
|
+
instance.extend const_get("#{type}Hooks")
|
110
|
+
end
|
111
|
+
|
112
|
+
MUTATION_METHODS.each do |klass, methods|
|
113
|
+
methods.each do |meth|
|
114
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
115
|
+
module #{klass}Hooks
|
116
|
+
def #{meth}(*)
|
117
|
+
before = self.clone
|
118
|
+
ret = super
|
119
|
+
after = self
|
120
|
+
|
121
|
+
# If the hashes aren't equivalent then we know the Resource
|
122
|
+
# should be dirty. However because we mutated self, normal
|
123
|
+
# State tracking will never trigger, because it will compare the
|
124
|
+
# new value - self - to the Resource's existing property value -
|
125
|
+
# which is also self.
|
126
|
+
#
|
127
|
+
# The solution is to drop 1 level beneath Resource State
|
128
|
+
# tracking and set the value of the property directly to the
|
129
|
+
# previous value (a different object now, because it's a clone).
|
130
|
+
# Then trigger the State tracking like normal.
|
131
|
+
if before.hash != after.hash
|
132
|
+
@property.set(@resource, before)
|
133
|
+
@resource.attribute_set(@property.name, after)
|
134
|
+
end
|
135
|
+
|
136
|
+
ret
|
137
|
+
end
|
138
|
+
end
|
139
|
+
RUBY
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def track(resource, property)
|
144
|
+
@resource, @property = resource, property
|
145
|
+
end
|
146
|
+
|
147
|
+
end # Hooker
|
148
|
+
|
149
|
+
# Catch any direct assignment (#set), and any Resource#reload (set!).
|
150
|
+
def set!(resource, value)
|
151
|
+
hook_value(resource, value) unless value.kind_of? Hooker
|
152
|
+
super
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def hook_value(resource, value)
|
158
|
+
return if value.kind_of? Hooker
|
159
|
+
|
160
|
+
value.extend Hooker
|
161
|
+
value.track(resource, self)
|
162
|
+
end
|
163
|
+
|
164
|
+
end # DirtyMinder
|
165
|
+
end # Property
|
166
|
+
end # DataMapper
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module DataMapper
|
2
|
+
class Property
|
3
|
+
module Flags
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
6
|
+
extend DataMapper::Property::Flags::ClassMethods
|
7
|
+
|
8
|
+
accept_options :flags
|
9
|
+
attr_reader :flag_map
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :generated_classes
|
13
|
+
end
|
14
|
+
|
15
|
+
self.generated_classes = {}
|
16
|
+
RUBY
|
17
|
+
end
|
18
|
+
|
19
|
+
def custom?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
# TODO: document
|
25
|
+
# @api public
|
26
|
+
def [](*values)
|
27
|
+
if klass = generated_classes[values.flatten]
|
28
|
+
klass
|
29
|
+
else
|
30
|
+
klass = ::Class.new(self)
|
31
|
+
klass.flags(values)
|
32
|
+
|
33
|
+
generated_classes[values.flatten] = klass
|
34
|
+
|
35
|
+
klass
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/dm-types/uri.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
require 'dm-core'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
class Property
|
6
|
+
class URI < String
|
7
|
+
|
8
|
+
# Maximum length chosen based on recommendation:
|
9
|
+
# http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-an-url
|
10
|
+
length 2000
|
11
|
+
|
12
|
+
def custom?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def primitive?(value)
|
17
|
+
value.kind_of?(Addressable::URI)
|
18
|
+
end
|
19
|
+
|
20
|
+
def valid?(value, negated = false)
|
21
|
+
super || primitive?(value) || value.kind_of?(::String)
|
22
|
+
end
|
23
|
+
|
24
|
+
def load(value)
|
25
|
+
Addressable::URI.parse(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def dump(value)
|
29
|
+
value.to_s unless value.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def typecast_to_primitive(value)
|
33
|
+
load(value)
|
34
|
+
end
|
35
|
+
|
36
|
+
end # class URI
|
37
|
+
end # class Property
|
38
|
+
end # module DataMapper
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'uuidtools' # must be ~>2.0
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
class Property
|
6
|
+
# UUID Type
|
7
|
+
# First run at this, because I need it. A few caveats:
|
8
|
+
# * Only works on postgres, using the built-in native uuid type.
|
9
|
+
# To make it work in mysql, you'll have to add a typemap entry to
|
10
|
+
# the mysql_adapter. I think. I don't have mysql handy, so I'm
|
11
|
+
# not going to try. For SQLite, this will have to inherit from the
|
12
|
+
# String primitive
|
13
|
+
# * Won't accept a random default, because of the namespace clash
|
14
|
+
# between this and the UUIDtools gem. Also can't set the default
|
15
|
+
# type to UUID() (postgres-contrib's native generator) and
|
16
|
+
# automigrate, because auto_migrate! tries to make it a string "UUID()"
|
17
|
+
# Feel free to enchance this, and delete these caveats when they're fixed.
|
18
|
+
#
|
19
|
+
# -- Rando Sept 25, 08
|
20
|
+
#
|
21
|
+
# Actually, setting the primitive to "UUID" is not neccessary and causes
|
22
|
+
# a segfault when trying to query uuid's from the database. The primitive
|
23
|
+
# should be a class which has been added to the do driver you are using.
|
24
|
+
# Also, it's only neccessary to add a class to the do drivers to use as a
|
25
|
+
# primitive when a value cannot be represented as a string. A uuid can be
|
26
|
+
# represented as a string, so setting the primitive to String ensures that
|
27
|
+
# the value argument is a String containing the uuid in string form.
|
28
|
+
#
|
29
|
+
# <strike>It is still neccessary to add the UUID entry to the type map for
|
30
|
+
# each different adapter with their respective database primitive.</strike>
|
31
|
+
#
|
32
|
+
# The method that generates the SQL schema from the typemap currently
|
33
|
+
# ignores the size attribute from the type map if the primitive type
|
34
|
+
# is String. The causes the generated SQL statement to contain a size for
|
35
|
+
# a UUID column (e.g. id UUID(50)), which causes a syntax error in postgres.
|
36
|
+
# Until this is resolved, you will have to manually change the column type
|
37
|
+
# to UUID in a migration, if you want to use postgres' built in UUID type.
|
38
|
+
#
|
39
|
+
# -- benburkert Nov 15, 08
|
40
|
+
#
|
41
|
+
class UUID < String
|
42
|
+
|
43
|
+
length 36
|
44
|
+
|
45
|
+
# We need to override this method otherwise typecast_to_primitive won't be called.
|
46
|
+
# In the future we will set primitive to UUIDTools::UUID but this can happen only
|
47
|
+
# when adapters can handle it
|
48
|
+
def primitive?(value)
|
49
|
+
value.kind_of?(UUIDTools::UUID)
|
50
|
+
end
|
51
|
+
|
52
|
+
def valid?(value, negated = false)
|
53
|
+
super || dump(value).kind_of?(::String)
|
54
|
+
end
|
55
|
+
|
56
|
+
def dump(value)
|
57
|
+
value.to_s unless value.nil?
|
58
|
+
end
|
59
|
+
|
60
|
+
def load(value)
|
61
|
+
if primitive?(value)
|
62
|
+
value
|
63
|
+
elsif !value.nil?
|
64
|
+
UUIDTools::UUID.parse(value)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def typecast_to_primitive(value)
|
69
|
+
load(value)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'dm-core'
|
3
|
+
require 'dm-types/support/dirty_minder'
|
4
|
+
|
5
|
+
module DataMapper
|
6
|
+
class Property
|
7
|
+
class Yaml < Text
|
8
|
+
|
9
|
+
def custom?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(value)
|
14
|
+
if value.nil?
|
15
|
+
nil
|
16
|
+
elsif value.is_a?(::String)
|
17
|
+
::YAML.load(value)
|
18
|
+
else
|
19
|
+
raise ArgumentError, '+value+ of a property of YAML type must be nil or a String'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def dump(value)
|
24
|
+
if value.nil?
|
25
|
+
nil
|
26
|
+
elsif value.is_a?(::String) && value =~ /^---/
|
27
|
+
value
|
28
|
+
else
|
29
|
+
::YAML.dump(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def typecast(value)
|
34
|
+
value
|
35
|
+
end
|
36
|
+
|
37
|
+
include ::DataMapper::Property::DirtyMinder
|
38
|
+
|
39
|
+
end # class Yaml
|
40
|
+
end # class Property
|
41
|
+
end # module DataMapper
|
data/lib/dm-types.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
class Property
|
5
|
+
autoload :CommaSeparatedList, 'dm-types/comma_separated_list'
|
6
|
+
autoload :Csv, 'dm-types/csv'
|
7
|
+
autoload :BCryptHash, 'dm-types/bcrypt_hash'
|
8
|
+
autoload :Enum, 'dm-types/enum'
|
9
|
+
autoload :EpochTime, 'dm-types/epoch_time'
|
10
|
+
autoload :FilePath, 'dm-types/file_path'
|
11
|
+
autoload :Flag, 'dm-types/flag'
|
12
|
+
autoload :IPAddress, 'dm-types/ip_address'
|
13
|
+
autoload :Json, 'dm-types/json'
|
14
|
+
autoload :Regexp, 'dm-types/regexp'
|
15
|
+
autoload :ParanoidBoolean, 'dm-types/paranoid_boolean'
|
16
|
+
autoload :ParanoidDateTime, 'dm-types/paranoid_datetime'
|
17
|
+
autoload :Slug, 'dm-types/slug'
|
18
|
+
autoload :UUID, 'dm-types/uuid'
|
19
|
+
autoload :URI, 'dm-types/uri'
|
20
|
+
autoload :Yaml, 'dm-types/yaml'
|
21
|
+
autoload :APIKey, 'dm-types/api_key'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module TypesFixtures
|
3
|
+
|
4
|
+
class Article
|
5
|
+
#
|
6
|
+
# Behaviors
|
7
|
+
#
|
8
|
+
|
9
|
+
include ::DataMapper::Resource
|
10
|
+
|
11
|
+
#
|
12
|
+
# Properties
|
13
|
+
#
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
|
17
|
+
property :title, String, :length => 255
|
18
|
+
property :body, Text
|
19
|
+
|
20
|
+
property :created_at, DateTime
|
21
|
+
property :updated_at, DateTime
|
22
|
+
property :published_at, DateTime
|
23
|
+
|
24
|
+
property :slug, Slug
|
25
|
+
|
26
|
+
#
|
27
|
+
# Hooks
|
28
|
+
#
|
29
|
+
|
30
|
+
before :valid? do
|
31
|
+
self.slug = self.title
|
32
|
+
end
|
33
|
+
end # Article
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module TypesFixtures
|
3
|
+
|
4
|
+
class Bookmark
|
5
|
+
#
|
6
|
+
# Behaviors
|
7
|
+
#
|
8
|
+
|
9
|
+
include ::DataMapper::Resource
|
10
|
+
|
11
|
+
#
|
12
|
+
# Properties
|
13
|
+
#
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
|
17
|
+
property :title, String, :length => 255
|
18
|
+
property :shared, Boolean
|
19
|
+
property :uri, URI
|
20
|
+
property :tags, Yaml
|
21
|
+
end # Bookmark
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module TypesFixtures
|
3
|
+
|
4
|
+
class NetworkNode
|
5
|
+
#
|
6
|
+
# Behaviors
|
7
|
+
#
|
8
|
+
|
9
|
+
include ::DataMapper::Resource
|
10
|
+
|
11
|
+
#
|
12
|
+
# Properties
|
13
|
+
#
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
property :ip_address, IPAddress
|
17
|
+
property :cidr_subnet_bits, Integer
|
18
|
+
property :node_uuid, UUID
|
19
|
+
|
20
|
+
#
|
21
|
+
# API
|
22
|
+
#
|
23
|
+
|
24
|
+
alias_method :uuid, :node_uuid
|
25
|
+
alias_method :uuid=, :node_uuid=
|
26
|
+
|
27
|
+
def runs_ipv6?
|
28
|
+
self.ip_address.ipv6?
|
29
|
+
end
|
30
|
+
|
31
|
+
def runs_ipv4?
|
32
|
+
self.ip_address.ipv4?
|
33
|
+
end
|
34
|
+
end # NetworkNode
|
35
|
+
end # TypesFixtures
|
36
|
+
end # DataMapper
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module TypesFixtures
|
3
|
+
class Person
|
4
|
+
#
|
5
|
+
# Behaviors
|
6
|
+
#
|
7
|
+
|
8
|
+
include DataMapper::Resource
|
9
|
+
|
10
|
+
#
|
11
|
+
# Properties
|
12
|
+
#
|
13
|
+
|
14
|
+
property :id, Serial
|
15
|
+
property :name, String
|
16
|
+
property :positions, Json
|
17
|
+
property :inventions, Yaml
|
18
|
+
property :birthday, EpochTime
|
19
|
+
|
20
|
+
property :interests, CommaSeparatedList
|
21
|
+
|
22
|
+
property :password, BCryptHash
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module TypesFixtures
|
3
|
+
|
4
|
+
class SoftwarePackage
|
5
|
+
#
|
6
|
+
# Behaviors
|
7
|
+
#
|
8
|
+
|
9
|
+
include ::DataMapper::Resource
|
10
|
+
|
11
|
+
#
|
12
|
+
# Properties
|
13
|
+
#
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
without_auto_validations do
|
17
|
+
property :node_number, Integer, :index => true
|
18
|
+
|
19
|
+
property :source_path, FilePath
|
20
|
+
property :destination_path, FilePath
|
21
|
+
|
22
|
+
property :product, String
|
23
|
+
property :version, String
|
24
|
+
property :released_at, DateTime
|
25
|
+
|
26
|
+
property :security_update, Boolean
|
27
|
+
|
28
|
+
property :installed_at, DateTime
|
29
|
+
property :installed_by, String
|
30
|
+
end
|
31
|
+
end # SoftwarePackage
|
32
|
+
end # TypesFixtures
|
33
|
+
end # DataMapper
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module TypesFixtures
|
3
|
+
class Ticket
|
4
|
+
#
|
5
|
+
# Behaviors
|
6
|
+
#
|
7
|
+
|
8
|
+
include DataMapper::Resource
|
9
|
+
include DataMapper::Validations
|
10
|
+
|
11
|
+
#
|
12
|
+
# Properties
|
13
|
+
#
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
property :title, String, :length => 255
|
17
|
+
property :body, Text
|
18
|
+
property :status, Enum[:unconfirmed, :confirmed, :assigned, :resolved, :not_applicable]
|
19
|
+
end # Ticket
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module TypesFixtures
|
3
|
+
|
4
|
+
class TShirt
|
5
|
+
#
|
6
|
+
# Behaviors
|
7
|
+
#
|
8
|
+
|
9
|
+
include ::DataMapper::Resource
|
10
|
+
|
11
|
+
#
|
12
|
+
# Properties
|
13
|
+
#
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
property :writing, String
|
17
|
+
property :has_picture, Boolean, :default => false
|
18
|
+
property :picture, Enum[:octocat, :fork_you, :git_down]
|
19
|
+
|
20
|
+
property :color, Enum[:white, :black, :red, :orange, :yellow, :green, :cyan, :blue, :purple]
|
21
|
+
property :size, Flag[:xs, :small, :medium, :large, :xl, :xxl], :default => :xs
|
22
|
+
end # Shirt
|
23
|
+
end # TypesFixtures
|
24
|
+
end # DataMapper
|