-
Notifications
You must be signed in to change notification settings - Fork 152
/
properties.rb
74 lines (65 loc) · 2.41 KB
/
properties.rb
1
2
3
4
5
6
7
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
require 'ripple/core_ext/casting'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/indifferent_access'
module Ripple
# Adds the ability to declare properties on your Ripple::Document class.
# Properties will automatically generate accessor (get/set/query) methods and
# handle type-casting between your Ruby type and JSON-compatible types.
module Properties
# @private
def inherited(subclass)
super
subclass.properties.merge!(properties)
end
# @return [Hash] the properties defined on the document
def properties
@properties ||= {}.with_indifferent_access
end
def property(key, type, options={})
prop = Property.new(key, type, options)
properties[prop.key] = prop
end
end
# Encapsulates a single property on your Ripple::Document class.
class Property
# @return [Symbol] the key of this property in the Document
attr_reader :key
# @return [Class] the Ruby type of property.
attr_reader :type
# @return [Hash] configuration options
attr_reader :options
# Create a new document property.
# @param [String, Symbol] key the key of the property
# @param [Class] type the Ruby type of the property. Use {Boolean} for true or false types.
# @param [Hash] options configuration options
# @option options [Object, Proc] :default (nil) a default value
# for the property, or a lambda to evaluate when providing the default.
def initialize(key, type, options={})
@options = options.to_options
@key = key.to_sym
@type = type
end
# @return [Object] The default value for this property if defined, or nil.
def default
default = options[:default]
default = default.dup if default.duplicable?
return nil if default.nil?
type_cast(default.respond_to?(:call) ? default.call : default)
end
# @return [Hash] options appropriate for the validates class method
def validation_options
@options.dup.except(:default)
end
# Attempt to coerce the passed value into this property's type
# @param [Object] value the value to coerce
# @return [Object] the value coerced into this property's type
# @raise [PropertyTypeMismatch] if the value cannot be coerced into the property's type
def type_cast(value)
if @type.respond_to?(:ripple_cast)
@type.ripple_cast(value)
else
value
end
end
end
end