traitr 0.0.6 → 0.0.7
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 +4 -4
- data/lib/traitor.rb +100 -13
- data/lib/traitor/config.rb +10 -6
- data/lib/traitor/helpers/active_record.rb +12 -1
- data/lib/traitor/helpers/rspec.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 989c4e5ac888058f57192ebbbc0e21729f574032
|
4
|
+
data.tar.gz: 21deba747d0819395e847d96bc73d976e62d2c40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e29befd886a056da95c916aed20ec0bb2933382acaf070d0e3a79341a5434cd023cc72964712ea10cf07b2c196faeb2ebb058f0e35aea1689a09ac58fa79bace
|
7
|
+
data.tar.gz: 18165a4221d8f9e44973920a786c4f196240af8cc245f30a0cd4efa30d316eb3ae1517d06fc2e5f3bbe9c31f7522bf40cd4baa5ef6b5d71ddfdb308d8d31cf6e
|
data/lib/traitor.rb
CHANGED
@@ -12,6 +12,7 @@ module Traitor
|
|
12
12
|
@trait_cache = {}
|
13
13
|
|
14
14
|
class << self
|
15
|
+
# Reset Traitor entirely by clearing its attributes.
|
15
16
|
def reset!
|
16
17
|
@trait_library = {}
|
17
18
|
@alternate_create_methods = {}
|
@@ -20,6 +21,10 @@ module Traitor
|
|
20
21
|
@trait_cache = {}
|
21
22
|
end
|
22
23
|
|
24
|
+
# Hook an object into Traitor. Read GETTING_STARTED.md for assistance.
|
25
|
+
#
|
26
|
+
# @param [String|Symbol] klass - the class reference.
|
27
|
+
# @param [Hash] traits - the hash of traits defined on the Traitor.s
|
23
28
|
def define(klass, **traits)
|
24
29
|
@trait_library[klass] ||= {}
|
25
30
|
|
@@ -47,11 +52,20 @@ module Traitor
|
|
47
52
|
@trait_library[klass].merge!(traits)
|
48
53
|
end
|
49
54
|
|
50
|
-
##
|
51
55
|
# build an instance of an object using the defined traits and attributes.
|
52
|
-
|
56
|
+
#
|
57
|
+
# @param [String|Symbol] klass - the class reference symbol to get the library from
|
58
|
+
# @param [Array] traits - the list of traits to refer attributes from
|
59
|
+
# @param [Hash] attributes - the list of attributes to apply to the specific object.
|
53
60
|
def build(klass, *traits, **attributes)
|
54
|
-
|
61
|
+
attrs, concat_attrs = split_attributes(attributes)
|
62
|
+
attributes = get_attributes_from_traits(klass, traits).merge(attrs)
|
63
|
+
# but add all the separate concatenated attributes into a list.
|
64
|
+
concat_attrs.each do |k, v|
|
65
|
+
attributes[k] ||= []
|
66
|
+
attributes[k] << v
|
67
|
+
end
|
68
|
+
|
55
69
|
build_kwargs = Traitor::Config.build_kwargs || {}
|
56
70
|
|
57
71
|
record = if Traitor::Config.build_with_list
|
@@ -66,10 +80,12 @@ module Traitor
|
|
66
80
|
record
|
67
81
|
end
|
68
82
|
|
69
|
-
##
|
70
83
|
# build an instance of an object using the defined traits and attributes,
|
71
|
-
# and then save it.
|
72
|
-
|
84
|
+
# and then save it using the appropriate create method.
|
85
|
+
#
|
86
|
+
# @param [String|Symbol] klass - the class reference symbol to get the library from
|
87
|
+
# @param [Array] traits - the list of traits to refer attributes from
|
88
|
+
# @param [Hash] attributes - the list of attributes to apply to the specific object.
|
73
89
|
def create(klass, *traits, **attributes)
|
74
90
|
create_method, create_kwargs = @alternate_create_methods[klass] ||
|
75
91
|
[Traitor::Config.create_method, Traitor::Config.create_kwargs || {}]
|
@@ -88,6 +104,12 @@ module Traitor
|
|
88
104
|
record
|
89
105
|
end
|
90
106
|
|
107
|
+
# build an instance of an object using the defined traits and attributes,
|
108
|
+
# and then save it using the explicitly referenced create method.
|
109
|
+
#
|
110
|
+
# @param [String|Symbol] klass - the class reference symbol to get the library from
|
111
|
+
# @param [Array] traits - the list of traits to refer attributes from
|
112
|
+
# @param [Hash] attributes - the list of attributes to apply to the specific object.
|
91
113
|
def create_using(klass, create_method, *traits, **attributes)
|
92
114
|
old_create_method_kwargs = @alternate_create_methods[klass]
|
93
115
|
@alternate_create_methods[klass] = [create_method, attributes.delete(:create_kwargs) || {}]
|
@@ -98,6 +120,14 @@ module Traitor
|
|
98
120
|
|
99
121
|
private
|
100
122
|
|
123
|
+
# Helper method to call after blocks that are defined on a Traitor.
|
124
|
+
#
|
125
|
+
# @param [String|Symbol] klass - the class reference for the library.
|
126
|
+
# @param [Symbol] trigger - one of the values in BLOCK_KEYS, to check for in
|
127
|
+
# the block library.
|
128
|
+
# @param [Object] record - the object the trigger will yield.
|
129
|
+
# @param [Array] traits - A list of traits that the object was built with,
|
130
|
+
# to find any triggers specific to the referenced traits.
|
101
131
|
def call_blocks(klass, trigger, record, *traits)
|
102
132
|
return unless @block_library[klass]
|
103
133
|
[].tap do |blocks|
|
@@ -110,12 +140,26 @@ module Traitor
|
|
110
140
|
end.compact.each { |block| block.call(record) }
|
111
141
|
end
|
112
142
|
|
143
|
+
# given a string/symbol, return the class based on that symbol.
|
144
|
+
# e.g. :some_class -> SomeClass
|
145
|
+
#
|
146
|
+
# @param [String|Symbol] klass - the class symbol/reference
|
147
|
+
# @return [Object] the class
|
113
148
|
def convert_to_class(klass)
|
114
149
|
@class_cache[klass] ||= Object.const_get(camelize(klass))
|
115
150
|
rescue NameError
|
116
151
|
raise Traitor::Error.new("Tried to create a #{camelize(klass)}, but it does not exist!")
|
117
152
|
end
|
118
153
|
|
154
|
+
# Given a list of traits, return the compiled hash of attributes with calculated values.
|
155
|
+
# Will properly call lambdas/procs to get their value and will concatenate attributes
|
156
|
+
# prefixed with a '+'.
|
157
|
+
#
|
158
|
+
# Will always start from the :default_traits trait, if it exists.
|
159
|
+
#
|
160
|
+
# @param [String|Symbol] klass - the class reference to get the list of traits from the library.
|
161
|
+
# @param [Array[String|Symbol]] traits - a list of traits to refer to in the library.
|
162
|
+
# @return [Hash] The calculated attributes hash.
|
119
163
|
def get_attributes_from_traits(klass, traits)
|
120
164
|
# we only call this method when the klass has been converted to a key inside create
|
121
165
|
return {} unless library = @trait_library[klass]
|
@@ -124,23 +168,66 @@ module Traitor
|
|
124
168
|
|
125
169
|
cache_key = klass.to_s + ':' + traits.join(':')
|
126
170
|
@trait_cache[cache_key] ||= {}.tap do |attributes|
|
127
|
-
traits.each
|
171
|
+
traits.each do |trait|
|
172
|
+
# pull out concatenating attributes into their own list
|
173
|
+
attrs, concat_attrs = split_attributes(library[trait] || {})
|
174
|
+
|
175
|
+
# raw merge in the standard attributes...
|
176
|
+
attributes.merge!(attrs)
|
177
|
+
|
178
|
+
# but add all the separate concatenated attributes into a list.
|
179
|
+
concat_attrs.each do |k, v|
|
180
|
+
attributes[k] ||= []
|
181
|
+
attributes[k] << v
|
182
|
+
end
|
183
|
+
end
|
128
184
|
end
|
129
185
|
|
130
186
|
# use late resolution on lambda values by calling them here as part of constructing a new hash
|
131
187
|
Hash[
|
132
188
|
@trait_cache[cache_key].map do |attribute, value|
|
133
|
-
[attribute, value
|
189
|
+
[attribute, calculate_value(value)]
|
134
190
|
end
|
135
191
|
]
|
136
192
|
end
|
137
193
|
|
194
|
+
# Split a hash into two hashes, the first being a list of all values that do
|
195
|
+
# not begin with '+', the latter being a list of all values that do.
|
196
|
+
#
|
197
|
+
# @param [Hash] attributes
|
198
|
+
# @return [Array[Hash, Hash]] The split hash.
|
199
|
+
def split_attributes(attributes)
|
200
|
+
attributes.reduce([{}, {}]) do |memo, attr_val|
|
201
|
+
attribute, value = attr_val
|
202
|
+
if attribute.to_s.start_with?('+')
|
203
|
+
memo[1][attribute[1..-1].to_sym] = value
|
204
|
+
else
|
205
|
+
memo[0][attribute] = value
|
206
|
+
end
|
207
|
+
memo
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Given the value reference from an attribute, call it if callable, or map it
|
212
|
+
# if appropriate, or return it as-is.
|
213
|
+
#
|
214
|
+
# @param [Mixed] v - the value from an attribute. can be Proc, Array, or "value"
|
215
|
+
# @return the calculated value.
|
216
|
+
def calculate_value(v)
|
217
|
+
return v.call if v.is_a?(Proc)
|
218
|
+
return v.map { |sv| calculate_value(sv) } if v.is_a?(Array)
|
219
|
+
v
|
220
|
+
end
|
221
|
+
|
222
|
+
# simplifed version of ActiveRecord camelize.
|
223
|
+
# used to convert a generic class name (in)
|
224
|
+
#
|
225
|
+
# @param [String|Symbol] term - the term to symbolize
|
226
|
+
# @return [String] the camel-cased version of the term, to be retrieved as a const.
|
138
227
|
def camelize(term)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
string.gsub!('/'.freeze, '::'.freeze)
|
143
|
-
string
|
228
|
+
term.to_s.capitalize
|
229
|
+
.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
230
|
+
.gsub('/'.freeze, '::'.freeze)
|
144
231
|
end
|
145
232
|
end
|
146
233
|
end
|
data/lib/traitor/config.rb
CHANGED
@@ -12,29 +12,33 @@ module Traitor
|
|
12
12
|
def configure_for_rails!
|
13
13
|
@create_method = :save
|
14
14
|
@create_kwargs = { validate: false }
|
15
|
-
@build_kwargs
|
15
|
+
@build_kwargs = { without_protection: true }
|
16
16
|
end
|
17
17
|
|
18
18
|
def configure_safe_for_rails!
|
19
19
|
@create_method = :save
|
20
20
|
@create_kwargs = {}
|
21
|
-
@build_kwargs
|
21
|
+
@build_kwargs = {}
|
22
22
|
end
|
23
23
|
|
24
|
+
# Undefine all configuration values.
|
24
25
|
def reset!
|
25
|
-
@create_method
|
26
|
-
@create_kwargs
|
27
|
-
@build_kwargs
|
26
|
+
@create_method = nil
|
27
|
+
@create_kwargs = {}
|
28
|
+
@build_kwargs = {}
|
28
29
|
@build_with_list = false
|
29
|
-
@no_callbacks
|
30
|
+
@no_callbacks = false
|
30
31
|
end
|
31
32
|
|
33
|
+
# Temporarily store the old configuration, so the config can be modified and
|
34
|
+
# then later restored.
|
32
35
|
def stash!
|
33
36
|
@old_config = Hash[
|
34
37
|
self.instance_variables.map { |att| [att, self.instance_variable_get(att)] }
|
35
38
|
]
|
36
39
|
end
|
37
40
|
|
41
|
+
# After calling #stash!, call this to restore the stashed config.
|
38
42
|
def restore!
|
39
43
|
return unless @old_config
|
40
44
|
@old_config.each { |att, val| self.instance_variable_set(att, val) }
|
@@ -29,6 +29,7 @@ module Traitor
|
|
29
29
|
self.class.connection.execute(insert_sql)
|
30
30
|
id = self.maximum(pk)
|
31
31
|
self.send(:"#{pk}=", id)
|
32
|
+
self.instance_variable_set(:@new_record, false)
|
32
33
|
self.clear_changes_information
|
33
34
|
end
|
34
35
|
|
@@ -43,6 +44,7 @@ module Traitor
|
|
43
44
|
pk = self.class.primary_key
|
44
45
|
id = conn.execute("SELECT last_insert_rowid() AS id")[0]['id']
|
45
46
|
self.send(:"#{pk}=", id)
|
47
|
+
self.instance_variable_set(:@new_record, false)
|
46
48
|
self.clear_changes_information
|
47
49
|
end
|
48
50
|
|
@@ -58,7 +60,16 @@ module Traitor
|
|
58
60
|
end.to_sql
|
59
61
|
|
60
62
|
# return and assign everything to gather values created/modified by db triggers
|
61
|
-
|
63
|
+
result = self.class.connection.execute(insert_sql + " RETURNING *")
|
64
|
+
|
65
|
+
# reassign the write values back to the object, in case there are DB triggers.
|
66
|
+
result.to_a.first.each do |column_name, serialized_value|
|
67
|
+
column = self.column_for_attribute(column_name)
|
68
|
+
deserialized_value = column.type_cast_from_database(serialized_value)
|
69
|
+
self["#{column_name}"] = deserialized_value
|
70
|
+
end
|
71
|
+
|
72
|
+
# mark the instance as having been saved.
|
62
73
|
self.instance_variable_set(:@new_record, false)
|
63
74
|
self.clear_changes_information
|
64
75
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: traitr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Lome
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|