modelish 0.3.0 → 1.0.0.pre.1
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 +2 -0
- data/.rspec +3 -1
- data/.ruby-version +1 -1
- data/.travis.yml +14 -0
- data/Appraisals +11 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +5 -1
- data/README.md +5 -0
- data/gemfiles/hashie_1.gemfile +7 -0
- data/gemfiles/hashie_2.gemfile +7 -0
- data/gemfiles/hashie_3.gemfile +7 -0
- data/lib/modelish/base.rb +108 -72
- data/lib/modelish/configuration.rb +9 -8
- data/lib/modelish/property_translations.rb +23 -11
- data/lib/modelish/property_types.rb +67 -50
- data/lib/modelish/validations.rb +70 -51
- data/lib/modelish/version.rb +3 -1
- data/lib/modelish.rb +3 -1
- data/modelish.gemspec +20 -15
- data/spec/modelish/base_spec.rb +203 -182
- data/spec/modelish/configuration_spec.rb +26 -19
- data/spec/modelish/property_translations_spec.rb +47 -39
- data/spec/modelish/property_types_spec.rb +53 -45
- data/spec/modelish/validations_spec.rb +296 -256
- data/spec/modelish_spec.rb +5 -3
- data/spec/spec_helper.rb +97 -2
- data/spec/support/property_examples.rb +15 -12
- data/spec/support/typed_property_examples.rb +39 -35
- data/spec/support/unknown_property_examples.rb +6 -4
- data/spec/support/validation_examples.rb +29 -23
- metadata +136 -103
- data/.ruby-gemset +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ebd460629d89807f4466c496083fd9a0a7be54d5
|
4
|
+
data.tar.gz: 667ce55093567f11e2d0c4a5f108828d5c3808fa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7414d42602a180112990808d9ce895ad9da82ba6dc19dc9dc69d6967286b986260ae8d9ba8bfaa4c5842d508fc12fdfb902c56567e72ae4f8a1019afc81e137d
|
7
|
+
data.tar.gz: ac6d7d3831e1854da332e0d6b14e0b2358f17e0a6e4baa0d1b326e995c5afc51ab76e7c257a38389673bb554692ee0600b32cd1610b9abcd48a0ea1dacd9090f
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.3.4
|
data/.travis.yml
ADDED
data/Appraisals
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 1.0.0.pre.1 (2017-06-11)
|
4
|
+
|
5
|
+
* **Backwards incompatible change**: dropped support for ruby 1.8.7
|
6
|
+
* Relax dependency on hashie to >= 1.0
|
7
|
+
* Add support for ruby 2.3 and 2.4
|
8
|
+
* General cleanup in dev and CI environments
|
9
|
+
|
10
|
+
## 0.4.0 (2017-06-08)
|
11
|
+
|
12
|
+
* **yanked** on 2017-06-11 because it broke compatibility with ruby 1.8.7
|
13
|
+
|
3
14
|
## 0.3.0 (2013-7-8)
|
4
15
|
|
5
16
|
* Upgrade hashie dependency to v2.0.x
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
When a real modeling framework is too heavy, sometimes you want something just
|
4
4
|
a little modelish.
|
5
5
|
|
6
|
+
**IMPORTANT NOTE**: modelish is considered legacy code at this point.
|
7
|
+
Maintenance will continue for bug fixes, but active development has ceased.
|
8
|
+
For new projects that require lightweight models, try looking at something like
|
9
|
+
[virtus](https://github.com/solnic/virtus) instead.
|
10
|
+
|
6
11
|
## Overview ##
|
7
12
|
|
8
13
|
If a Hash or OpenStruct almost suits your needs, but you need bits of
|
data/lib/modelish/base.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'hashie'
|
2
4
|
require 'modelish/property_translations'
|
3
5
|
require 'modelish/property_types'
|
@@ -5,69 +7,18 @@ require 'modelish/validations'
|
|
5
7
|
require 'modelish/configuration'
|
6
8
|
|
7
9
|
module Modelish
|
10
|
+
# Base class for all modelish objects
|
8
11
|
class Base < Hashie::Dash
|
9
12
|
include PropertyTranslations
|
10
13
|
include PropertyTypes
|
11
14
|
include Validations
|
12
15
|
extend Configuration
|
13
16
|
|
14
|
-
def initialize(options={}, &block)
|
17
|
+
def initialize(options = {}, &block)
|
15
18
|
super(&block)
|
16
19
|
|
17
20
|
attributes = options ? options.dup : {}
|
18
|
-
|
19
|
-
attributes.delete_if do |k,v|
|
20
|
-
if self.class.translations.keys.include?(k.to_sym)
|
21
|
-
self[k]=v
|
22
|
-
true
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
attributes.each_pair do |att, value|
|
27
|
-
self[att] = value
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Creates a new attribute.
|
32
|
-
#
|
33
|
-
# @param [Symbol] name the name of the property
|
34
|
-
# @param [Hash] options configuration for the property
|
35
|
-
# @option opts [Object] :default the default value for this property
|
36
|
-
# when the value has not been explicitly
|
37
|
-
# set (defaults to nil)
|
38
|
-
# @option opts [#to_s] :from the original key name for this attribute
|
39
|
-
# (created as write-only)
|
40
|
-
# @option opts [Class,Proc] :type the type of the property value. For
|
41
|
-
# a list of accepted types, see
|
42
|
-
# {Modelish::PropertyTypes}
|
43
|
-
# @option opts [true,false] :required enables validation for the property
|
44
|
-
# value's presence; nil or blank values
|
45
|
-
# will cause validation methods to fail
|
46
|
-
# @option opts [Integer] :max_length the maximum allowable length for a valid
|
47
|
-
# property value
|
48
|
-
# @option opts [true,false] :validate_type enables validation for the property value's
|
49
|
-
# type based on the :type option
|
50
|
-
# @option opts [Proc] :validator A block that accepts a value and validates it;
|
51
|
-
# should return nil if validation passes, or an error
|
52
|
-
# message or error object if validation fails.
|
53
|
-
# See {Modelish::Validations}
|
54
|
-
def self.property(name, options={})
|
55
|
-
|
56
|
-
#Hashie::Dash.property is going to delete :required from the options hash
|
57
|
-
required = options[:required]
|
58
|
-
|
59
|
-
super
|
60
|
-
|
61
|
-
add_property_type(name, options[:type]) if options[:type]
|
62
|
-
add_property_translation(options[:from], name) if options[:from]
|
63
|
-
|
64
|
-
if options[:required] || (self.respond_to?(:required?) && required?(name))
|
65
|
-
add_validator(name) { |val| validate_required(name => val).first }
|
66
|
-
end
|
67
|
-
|
68
|
-
add_validator(name) { |val| validate_length(name, val, options[:max_length]) } if options[:max_length]
|
69
|
-
add_validator(name, &options[:validator]) if options[:validator]
|
70
|
-
add_validator(name) { |val| validate_type(name, val, options[:type]) } if options[:validate_type]
|
21
|
+
init_attributes(attributes)
|
71
22
|
end
|
72
23
|
|
73
24
|
# Convert this Modelish object into a vanilla Hash with stringified keys.
|
@@ -75,15 +26,7 @@ module Modelish
|
|
75
26
|
# @return [Hash] the hash of properties
|
76
27
|
def to_hash
|
77
28
|
out = {}
|
78
|
-
self.class.properties.each
|
79
|
-
val = self.send(p)
|
80
|
-
if val.is_a?(Array)
|
81
|
-
out[p.to_s]||=[]
|
82
|
-
out[p.to_s].concat(val.collect{|x|x.respond_to?(:to_hash) ? x.to_hash : x})
|
83
|
-
else
|
84
|
-
out[p.to_s] = val.respond_to?(:to_hash) ? val.to_hash : val
|
85
|
-
end
|
86
|
-
end
|
29
|
+
self.class.properties.each { |p| out[hash_key(p)] = hash_value(p) }
|
87
30
|
out
|
88
31
|
end
|
89
32
|
|
@@ -96,27 +39,120 @@ module Modelish
|
|
96
39
|
end
|
97
40
|
|
98
41
|
private
|
42
|
+
|
43
|
+
def init_attributes(attributes)
|
44
|
+
attributes.delete_if do |k, v|
|
45
|
+
if self.class.translations.keys.include?(k.to_sym)
|
46
|
+
self[k] = v
|
47
|
+
true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
attributes.each_pair do |att, value|
|
52
|
+
self[att] = value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
99
56
|
def property_exists?(property)
|
100
57
|
if self.class.property?(property.to_sym)
|
101
58
|
true
|
102
|
-
elsif self.class.ignore_unknown_properties ||
|
103
|
-
(self.class.ignore_unknown_properties.nil? &&
|
59
|
+
elsif self.class.ignore_unknown_properties ||
|
60
|
+
(self.class.ignore_unknown_properties.nil? &&
|
61
|
+
Modelish.ignore_unknown_properties)
|
104
62
|
false
|
105
63
|
else
|
106
|
-
raise NoMethodError, "The property '#{property}' is not defined for
|
64
|
+
raise NoMethodError, "The property '#{property}' is not defined for " \
|
65
|
+
'this Modelish object.'
|
107
66
|
end
|
108
67
|
end
|
109
68
|
|
110
|
-
|
111
|
-
|
112
|
-
end
|
69
|
+
# Disable the various ways that hashie tries to assert required properties
|
70
|
+
# are set on initialization (modelish defers this until validation)
|
71
|
+
def assert_required_properties_set!; end
|
113
72
|
|
114
|
-
def assert_property_required!(
|
115
|
-
|
116
|
-
end
|
73
|
+
def assert_property_required!(_property, _value); end
|
74
|
+
|
75
|
+
def assert_required_attributes_set!; end
|
117
76
|
|
118
77
|
def assert_property_exists!(property)
|
119
78
|
property_exists?(property)
|
120
79
|
end
|
80
|
+
|
81
|
+
def hash_key(property)
|
82
|
+
property.to_s
|
83
|
+
end
|
84
|
+
|
85
|
+
def hash_value(property)
|
86
|
+
val = send(property)
|
87
|
+
|
88
|
+
if val.is_a?(Array)
|
89
|
+
val.map { |x| x.respond_to?(:to_hash) ? x.to_hash : x }
|
90
|
+
else
|
91
|
+
val.respond_to?(:to_hash) ? val.to_hash : val
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class << self
|
96
|
+
# Creates a new attribute.
|
97
|
+
#
|
98
|
+
# @param [Symbol] name the name of the property
|
99
|
+
# @param [Hash] options configuration for the property
|
100
|
+
# @option opts [Object] :default the default value for this property
|
101
|
+
# when the value has not been explicitly
|
102
|
+
# set (defaults to nil)
|
103
|
+
# @option opts [#to_s] :from the original key name for this attribute
|
104
|
+
# (created as write-only)
|
105
|
+
# @option opts [Class,Proc] :type the type of the property value. For
|
106
|
+
# a list of accepted types, see
|
107
|
+
# {Modelish::PropertyTypes}
|
108
|
+
# @option opts [true,false] :required enables validation for the property
|
109
|
+
# value's presence; nil or blank
|
110
|
+
# will cause validation to fail
|
111
|
+
# @option opts [Integer] :max_length the maximum allowable length for a
|
112
|
+
# valid property value
|
113
|
+
# @option opts [true,false] :validate_type enables validation for the
|
114
|
+
# property value's type based on
|
115
|
+
# the :type option
|
116
|
+
# @option opts [Proc] :validator A block that validates a value;
|
117
|
+
# returns nil if validation passes, or an
|
118
|
+
# error message or error object if
|
119
|
+
# validation fails.
|
120
|
+
# See {Modelish::Validations}
|
121
|
+
def property(name, options = {})
|
122
|
+
# Hashie::Dash.property deletes the :required key from the options
|
123
|
+
required = options[:required]
|
124
|
+
super
|
125
|
+
|
126
|
+
add_property_type(name, options[:type]) if options[:type]
|
127
|
+
add_property_translation(options[:from], name) if options[:from]
|
128
|
+
|
129
|
+
process_required(name) if required
|
130
|
+
process_max_length(name, options)
|
131
|
+
process_validate_type(name, options)
|
132
|
+
|
133
|
+
add_validator(name, &options[:validator]) if options[:validator]
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def process_required(name)
|
139
|
+
return unless respond_to?(:required?) && required?(name)
|
140
|
+
add_validator(name) { |val| validate_required(name => val).first }
|
141
|
+
end
|
142
|
+
|
143
|
+
def process_max_length(name, options)
|
144
|
+
return unless options[:max_length]
|
145
|
+
add_validator(name) do |val|
|
146
|
+
validate_length(name, val, options[:max_length])
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def process_validate_type(name, options)
|
151
|
+
return unless options[:validate_type]
|
152
|
+
add_validator(name) do |val|
|
153
|
+
validate_type(name, val, options[:type])
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
121
157
|
end
|
122
158
|
end
|
@@ -1,11 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Modelish
|
4
|
+
# Configure modelish's behavior on a global level
|
2
5
|
module Configuration
|
3
6
|
# If true, ignore unknown property names when initializing new models;
|
4
7
|
# otherwise, raise an error when an unknown property is encountered.
|
5
8
|
# Defaults to false.
|
6
9
|
attr_accessor :ignore_unknown_properties
|
7
10
|
|
8
|
-
# When set, unknown property names will be ignored during
|
11
|
+
# When set, unknown property names will be ignored during initialization
|
9
12
|
# and property setting.
|
10
13
|
#
|
11
14
|
# @see {raise_errors_on_unknown_properties!}
|
@@ -13,15 +16,16 @@ module Modelish
|
|
13
16
|
self.ignore_unknown_properties = true
|
14
17
|
end
|
15
18
|
|
16
|
-
# When set,
|
17
|
-
#
|
19
|
+
# When set, raise errors during initializeation and property setting when
|
20
|
+
# unknown property names are encountered. This is the default.
|
18
21
|
#
|
19
22
|
# @see {ignore_unknown_properties!}
|
20
23
|
def raise_errors_on_unknown_properties!
|
21
24
|
self.ignore_unknown_properties = false
|
22
25
|
end
|
23
26
|
|
24
|
-
# When this module is extended, set all configuration options to their
|
27
|
+
# When this module is extended, set all configuration options to their
|
28
|
+
# default values
|
25
29
|
def self.extended(base)
|
26
30
|
base.reset
|
27
31
|
end
|
@@ -35,10 +39,7 @@ module Modelish
|
|
35
39
|
# config.ignore_unknown_properties = true
|
36
40
|
# end
|
37
41
|
def configure
|
38
|
-
if block_given?
|
39
|
-
yield self
|
40
|
-
end
|
41
|
-
|
42
|
+
yield self if block_given?
|
42
43
|
self
|
43
44
|
end
|
44
45
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Modelish
|
2
4
|
# Mixin behavior for mapping one property name to another
|
3
5
|
module PropertyTranslations
|
@@ -5,6 +7,7 @@ module Modelish
|
|
5
7
|
base.extend(ClassMethods)
|
6
8
|
end
|
7
9
|
|
10
|
+
# Methods for managing a dictionary of property translations
|
8
11
|
module ClassMethods
|
9
12
|
# Adds a property translation to the model.
|
10
13
|
# This maps a mutator name to an existing property,
|
@@ -58,24 +61,33 @@ module Modelish
|
|
58
61
|
# @param [Symbol,String] from_name the name of the source property
|
59
62
|
# @param [Symbol,String] to_name the name of the destination property
|
60
63
|
def add_property_translation(from_name, to_name)
|
61
|
-
|
62
|
-
|
64
|
+
source = from_name.to_sym
|
65
|
+
target = to_name.to_sym
|
63
66
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
self.send("#{prop}=", value)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
67
|
+
translations[source] ||= []
|
68
|
+
translations[source] << target
|
69
|
+
define_writer_with_translations(source)
|
71
70
|
end
|
72
71
|
|
73
|
-
# A map of the
|
72
|
+
# A map of the configured property translations, keyed on from_name
|
74
73
|
#
|
75
|
-
# @return [Hash<Symbol,Array>]
|
74
|
+
# @return [Hash<Symbol,Array>] key is from_name, value is list of to_names
|
76
75
|
def translations
|
77
76
|
@translations ||= {}
|
78
77
|
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def define_writer_with_translations(source)
|
82
|
+
class_eval do
|
83
|
+
remove_method("#{source}=") if method_defined?("#{source}=")
|
84
|
+
define_method("#{source}=") do |value|
|
85
|
+
self.class.translations[source].each do |target|
|
86
|
+
send("#{target}=", value)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
79
91
|
end
|
80
92
|
end
|
81
93
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
|
3
5
|
module Modelish
|
@@ -7,21 +9,24 @@ module Modelish
|
|
7
9
|
base.extend(ClassMethods)
|
8
10
|
end
|
9
11
|
|
12
|
+
# Class methods for managing typed properties
|
10
13
|
module ClassMethods
|
11
14
|
# Adds a typed property to the model.
|
12
15
|
# This dynamically generates accessor/mutator methods that perform
|
13
16
|
# the appropriate type conversions on the property's value.
|
14
|
-
#
|
17
|
+
#
|
15
18
|
# Generated methods:
|
16
|
-
# * +<property_name>=(new_value)+ -- sets the property value.
|
17
|
-
# * +<property_name>+ -- returns the property value, converted to the
|
18
|
-
# type. If the value cannot be
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
19
|
+
# * +<property_name>=(new_value)+ -- sets the property value.
|
20
|
+
# * +<property_name>+ -- returns the property value, converted to the
|
21
|
+
# configured type. If the value cannot be
|
22
|
+
# converted, no error will be raised, and the raw
|
23
|
+
# unconverted value will be returned.
|
24
|
+
# * +<property_name>!+ -- returns the property value, converted to the
|
25
|
+
# configured type. If the value cannot be
|
26
|
+
# converted, a TypeError will be raised.
|
27
|
+
# * +raw_<property_name> -- the original property value, without any type
|
28
|
+
# conversions.
|
29
|
+
#
|
25
30
|
# @param [Symbol] property_name the name of the property.
|
26
31
|
# @param [Class, Proc] property_type the type of the property's value.
|
27
32
|
# Valid types include:
|
@@ -34,49 +39,57 @@ module Modelish
|
|
34
39
|
# * +String+
|
35
40
|
# * any arbitrary +Class+ -- will attempt conversion by passing the raw
|
36
41
|
# value into the class's initializer
|
37
|
-
# * an instance of +Proc+ -- will convert the value by executing the
|
38
|
-
# passing in the raw value
|
39
|
-
def add_property_type(property_name, property_type=String)
|
42
|
+
# * an instance of +Proc+ -- will convert the value by executing the
|
43
|
+
# proc, passing in the raw value
|
44
|
+
def add_property_type(property_name, property_type = String)
|
40
45
|
accessor = property_name.to_sym
|
46
|
+
return if property_types[accessor] == property_type
|
41
47
|
|
42
|
-
# TODO: Refactor. This method is getting unwieldy as more
|
48
|
+
# TODO: Refactor. This method is getting unwieldy as more
|
43
49
|
# corner cases are discovered. A few well-placed design
|
44
50
|
# refinements should take care of it (now we just need to figure
|
45
51
|
# out what those are.)
|
46
|
-
|
47
|
-
property_types[accessor] = property_type
|
48
|
-
|
49
|
-
raw_accessor = define_raw_accessor(accessor)
|
50
|
-
bang_accessor = define_bang_accessor(accessor)
|
52
|
+
property_types[accessor] = property_type
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
to_safe = "_to_safe_#{accessor}".to_sym
|
54
|
+
raw_accessor = define_raw_accessor(accessor)
|
55
|
+
bang_accessor = define_bang_accessor(accessor)
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
57
|
+
typed_accessor = "_typed_#{accessor}".to_sym
|
58
|
+
typed_mutator = "#{typed_accessor}=".to_sym
|
59
|
+
to_safe = "_to_safe_#{accessor}".to_sym
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
class_eval do
|
62
|
+
remove_method(typed_accessor) if method_defined?(typed_accessor)
|
63
|
+
remove_method(typed_mutator) if method_defined?(typed_mutator)
|
64
|
+
attr_accessor typed_accessor
|
65
|
+
protected typed_accessor, typed_mutator
|
66
|
+
|
67
|
+
remove_method(to_safe) if method_defined?(to_safe)
|
68
|
+
define_method(to_safe) do
|
69
|
+
begin
|
70
|
+
send(bang_accessor)
|
71
|
+
rescue
|
72
|
+
send(raw_accessor)
|
62
73
|
end
|
63
|
-
|
64
|
-
|
65
|
-
define_method(accessor) do
|
66
|
-
val = self.send(typed_accessor)
|
74
|
+
end
|
75
|
+
protected to_safe
|
67
76
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
77
|
+
remove_method(accessor) if method_defined?(accessor)
|
78
|
+
define_method(accessor) do
|
79
|
+
val = send(typed_accessor)
|
72
80
|
|
73
|
-
|
81
|
+
unless val || send(raw_accessor).nil?
|
82
|
+
val = send(to_safe)
|
83
|
+
send(typed_mutator, val)
|
74
84
|
end
|
75
85
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
86
|
+
val
|
87
|
+
end
|
88
|
+
|
89
|
+
remove_method("#{accessor}=") if method_defined?("#{accessor}=")
|
90
|
+
define_method("#{accessor}=") do |val|
|
91
|
+
send("#{raw_accessor}=", val)
|
92
|
+
send(typed_mutator, send(to_safe))
|
80
93
|
end
|
81
94
|
end
|
82
95
|
end
|
@@ -86,6 +99,7 @@ module Modelish
|
|
86
99
|
end
|
87
100
|
|
88
101
|
private
|
102
|
+
|
89
103
|
def define_raw_accessor(name)
|
90
104
|
accessor = name.to_sym
|
91
105
|
raw_accessor = "raw_#{name}".to_sym
|
@@ -112,9 +126,10 @@ module Modelish
|
|
112
126
|
converter = value_converter(property_types[property_name.to_sym])
|
113
127
|
|
114
128
|
class_eval do
|
129
|
+
remove_method(bang_accessor) if method_defined?(bang_accessor)
|
115
130
|
define_method(bang_accessor) do
|
116
|
-
value =
|
117
|
-
|
131
|
+
value = send("raw_#{property_name}")
|
132
|
+
converter && value ? converter.call(value) : value
|
118
133
|
end
|
119
134
|
end
|
120
135
|
|
@@ -123,19 +138,21 @@ module Modelish
|
|
123
138
|
|
124
139
|
def value_converter(property_type)
|
125
140
|
if [Date, DateTime].include?(property_type)
|
126
|
-
|
141
|
+
->(val) { property_type.parse(val.to_s) }
|
127
142
|
elsif property_type == Symbol
|
128
|
-
lambda
|
129
|
-
|
130
|
-
|
143
|
+
lambda do |val|
|
144
|
+
val.to_s.strip.gsub(/([A-Z]+)([A-Z][a-z])/, '\\1_\\2')
|
145
|
+
.gsub(/([a-z\d])([A-Z])/, '\\1_\\2')
|
146
|
+
.gsub(/\s+|-/, '_').downcase.to_sym
|
147
|
+
end
|
131
148
|
elsif property_type == String
|
132
|
-
|
133
|
-
elsif Kernel.respond_to?(property_type.to_s)
|
134
|
-
|
149
|
+
->(val) { val.to_s.strip }
|
150
|
+
elsif Kernel.respond_to?(property_type.to_s)
|
151
|
+
->(val) { Kernel.send(property_type.to_s, val) }
|
135
152
|
elsif property_type.respond_to?(:call)
|
136
153
|
property_type
|
137
154
|
else
|
138
|
-
|
155
|
+
->(val) { property_type.new(val) }
|
139
156
|
end
|
140
157
|
end
|
141
158
|
end
|