rom-core 4.0.0.beta1
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/CHANGELOG.md +603 -0
- data/LICENSE +20 -0
- data/README.md +18 -0
- data/lib/rom-core.rb +1 -0
- data/lib/rom/array_dataset.rb +44 -0
- data/lib/rom/association_set.rb +16 -0
- data/lib/rom/associations/abstract.rb +135 -0
- data/lib/rom/associations/definitions.rb +5 -0
- data/lib/rom/associations/definitions/abstract.rb +116 -0
- data/lib/rom/associations/definitions/many_to_many.rb +24 -0
- data/lib/rom/associations/definitions/many_to_one.rb +11 -0
- data/lib/rom/associations/definitions/one_to_many.rb +11 -0
- data/lib/rom/associations/definitions/one_to_one.rb +11 -0
- data/lib/rom/associations/definitions/one_to_one_through.rb +11 -0
- data/lib/rom/associations/many_to_many.rb +81 -0
- data/lib/rom/associations/many_to_one.rb +37 -0
- data/lib/rom/associations/one_to_many.rb +37 -0
- data/lib/rom/associations/one_to_one.rb +8 -0
- data/lib/rom/associations/one_to_one_through.rb +8 -0
- data/lib/rom/associations/through_identifier.rb +39 -0
- data/lib/rom/auto_curry.rb +55 -0
- data/lib/rom/cache.rb +46 -0
- data/lib/rom/command.rb +488 -0
- data/lib/rom/command_compiler.rb +239 -0
- data/lib/rom/command_proxy.rb +24 -0
- data/lib/rom/command_registry.rb +141 -0
- data/lib/rom/commands.rb +3 -0
- data/lib/rom/commands/class_interface.rb +270 -0
- data/lib/rom/commands/composite.rb +53 -0
- data/lib/rom/commands/create.rb +13 -0
- data/lib/rom/commands/delete.rb +14 -0
- data/lib/rom/commands/graph.rb +88 -0
- data/lib/rom/commands/graph/class_interface.rb +62 -0
- data/lib/rom/commands/graph/input_evaluator.rb +62 -0
- data/lib/rom/commands/lazy.rb +99 -0
- data/lib/rom/commands/lazy/create.rb +23 -0
- data/lib/rom/commands/lazy/delete.rb +27 -0
- data/lib/rom/commands/lazy/update.rb +34 -0
- data/lib/rom/commands/result.rb +96 -0
- data/lib/rom/commands/update.rb +14 -0
- data/lib/rom/configuration.rb +114 -0
- data/lib/rom/configuration_dsl.rb +87 -0
- data/lib/rom/configuration_dsl/command.rb +41 -0
- data/lib/rom/configuration_dsl/command_dsl.rb +35 -0
- data/lib/rom/configuration_dsl/relation.rb +26 -0
- data/lib/rom/configuration_plugin.rb +17 -0
- data/lib/rom/constants.rb +64 -0
- data/lib/rom/container.rb +147 -0
- data/lib/rom/core.rb +46 -0
- data/lib/rom/create_container.rb +60 -0
- data/lib/rom/data_proxy.rb +94 -0
- data/lib/rom/enumerable_dataset.rb +68 -0
- data/lib/rom/environment.rb +70 -0
- data/lib/rom/gateway.rb +184 -0
- data/lib/rom/global.rb +58 -0
- data/lib/rom/global/plugin_dsl.rb +47 -0
- data/lib/rom/initializer.rb +64 -0
- data/lib/rom/lint/enumerable_dataset.rb +54 -0
- data/lib/rom/lint/gateway.rb +120 -0
- data/lib/rom/lint/linter.rb +78 -0
- data/lib/rom/lint/spec.rb +20 -0
- data/lib/rom/lint/test.rb +98 -0
- data/lib/rom/mapper_registry.rb +24 -0
- data/lib/rom/memory.rb +4 -0
- data/lib/rom/memory/associations.rb +4 -0
- data/lib/rom/memory/associations/many_to_many.rb +10 -0
- data/lib/rom/memory/associations/many_to_one.rb +10 -0
- data/lib/rom/memory/associations/one_to_many.rb +10 -0
- data/lib/rom/memory/associations/one_to_one.rb +10 -0
- data/lib/rom/memory/commands.rb +56 -0
- data/lib/rom/memory/dataset.rb +97 -0
- data/lib/rom/memory/gateway.rb +64 -0
- data/lib/rom/memory/relation.rb +62 -0
- data/lib/rom/memory/schema.rb +23 -0
- data/lib/rom/memory/storage.rb +59 -0
- data/lib/rom/memory/types.rb +9 -0
- data/lib/rom/pipeline.rb +105 -0
- data/lib/rom/plugin.rb +25 -0
- data/lib/rom/plugin_base.rb +45 -0
- data/lib/rom/plugin_registry.rb +197 -0
- data/lib/rom/plugins/command/schema.rb +37 -0
- data/lib/rom/plugins/configuration/configuration_dsl.rb +21 -0
- data/lib/rom/plugins/relation/instrumentation.rb +51 -0
- data/lib/rom/plugins/relation/registry_reader.rb +44 -0
- data/lib/rom/plugins/schema/timestamps.rb +58 -0
- data/lib/rom/registry.rb +71 -0
- data/lib/rom/relation.rb +548 -0
- data/lib/rom/relation/class_interface.rb +282 -0
- data/lib/rom/relation/commands.rb +23 -0
- data/lib/rom/relation/composite.rb +46 -0
- data/lib/rom/relation/curried.rb +103 -0
- data/lib/rom/relation/graph.rb +197 -0
- data/lib/rom/relation/loaded.rb +127 -0
- data/lib/rom/relation/materializable.rb +66 -0
- data/lib/rom/relation/name.rb +111 -0
- data/lib/rom/relation/view_dsl.rb +64 -0
- data/lib/rom/relation/wrap.rb +83 -0
- data/lib/rom/relation_registry.rb +10 -0
- data/lib/rom/schema.rb +437 -0
- data/lib/rom/schema/associations_dsl.rb +195 -0
- data/lib/rom/schema/attribute.rb +419 -0
- data/lib/rom/schema/dsl.rb +164 -0
- data/lib/rom/schema/inferrer.rb +66 -0
- data/lib/rom/schema_plugin.rb +27 -0
- data/lib/rom/setup.rb +68 -0
- data/lib/rom/setup/auto_registration.rb +74 -0
- data/lib/rom/setup/auto_registration_strategies/base.rb +16 -0
- data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +63 -0
- data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +20 -0
- data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +18 -0
- data/lib/rom/setup/finalize.rb +103 -0
- data/lib/rom/setup/finalize/finalize_commands.rb +60 -0
- data/lib/rom/setup/finalize/finalize_mappers.rb +56 -0
- data/lib/rom/setup/finalize/finalize_relations.rb +135 -0
- data/lib/rom/support/configurable.rb +85 -0
- data/lib/rom/support/memoizable.rb +58 -0
- data/lib/rom/support/notifications.rb +103 -0
- data/lib/rom/transaction.rb +24 -0
- data/lib/rom/types.rb +26 -0
- data/lib/rom/version.rb +5 -0
- metadata +289 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
module ROM
|
2
|
+
# Abstract plugin base
|
3
|
+
#
|
4
|
+
# @private
|
5
|
+
class PluginBase
|
6
|
+
# @return [Module] a module representing the plugin
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
attr_reader :mod
|
10
|
+
|
11
|
+
# @return [Hash] configuration options
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
attr_reader :options
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
attr_reader :type
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def initialize(mod, options)
|
21
|
+
@mod = mod
|
22
|
+
@options = options
|
23
|
+
@type = options.fetch(:type)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def relation?
|
28
|
+
type == :relation
|
29
|
+
end
|
30
|
+
|
31
|
+
# @api private
|
32
|
+
def schema?
|
33
|
+
type == :schema
|
34
|
+
end
|
35
|
+
|
36
|
+
# Apply this plugin to the provided class
|
37
|
+
#
|
38
|
+
# @param [Mixed] base
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
def apply_to(_base)
|
42
|
+
raise NotImplementedError, "#{self.class}#apply_to not implemented"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'rom/registry'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
# Stores all registered plugins
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class PluginRegistry
|
8
|
+
# Internal registry for configuration plugins
|
9
|
+
#
|
10
|
+
# @return [ConfigurationPluginRegistry]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
attr_reader :configuration
|
14
|
+
|
15
|
+
# Internal registry for command plugins
|
16
|
+
#
|
17
|
+
# @return [InternalPluginRegistry]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
attr_reader :commands
|
21
|
+
|
22
|
+
# Internal registry for mapper plugins
|
23
|
+
#
|
24
|
+
# @return [InternalPluginRegistry]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
attr_reader :mappers
|
28
|
+
|
29
|
+
# Internal registry for relation plugins
|
30
|
+
#
|
31
|
+
# @return [InternalPluginRegistry]
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
attr_reader :relations
|
35
|
+
|
36
|
+
# Internal registry for schema plugins
|
37
|
+
#
|
38
|
+
# @return [InternalPluginRegistry]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
attr_reader :schemas
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
def initialize
|
45
|
+
@configuration = ConfigurationPluginRegistry.new
|
46
|
+
@mappers = InternalPluginRegistry.new
|
47
|
+
@commands = InternalPluginRegistry.new
|
48
|
+
@relations = InternalPluginRegistry.new
|
49
|
+
@schemas = InternalPluginRegistry.new(SchemaPlugin)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Register a plugin for future use
|
53
|
+
#
|
54
|
+
# @param [Symbol] name The registration name for the plugin
|
55
|
+
# @param [Module] mod The plugin to register
|
56
|
+
# @param [Hash] options optional configuration data
|
57
|
+
# @option options [Symbol] :type What type of plugin this is (command,
|
58
|
+
# relation or mapper)
|
59
|
+
# @option options [Symbol] :adapter (:default) which adapter this plugin
|
60
|
+
# applies to. Leave blank for all adapters
|
61
|
+
def register(name, mod, options = EMPTY_HASH)
|
62
|
+
type = options.fetch(:type)
|
63
|
+
adapter = options.fetch(:adapter, :default)
|
64
|
+
|
65
|
+
plugins_for(type, adapter).register(name, mod, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# Determine which specific registry to use
|
71
|
+
#
|
72
|
+
# @api private
|
73
|
+
def plugins_for(type, adapter)
|
74
|
+
case type
|
75
|
+
when :configuration then configuration
|
76
|
+
when :command then commands.adapter(adapter)
|
77
|
+
when :mapper then mappers.adapter(adapter)
|
78
|
+
when :relation then relations.adapter(adapter)
|
79
|
+
when :schema then schemas.adapter(adapter)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Abstract registry defining common behaviour
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
class PluginRegistryBase < Registry
|
88
|
+
include Dry::Equalizer(:elements, :plugin_type)
|
89
|
+
|
90
|
+
# !@attribute [r] plugin_type
|
91
|
+
# @return [Class] Typically ROM::PluginBase or its descendant
|
92
|
+
option :plugin_type
|
93
|
+
|
94
|
+
# Retrieve a registered plugin
|
95
|
+
#
|
96
|
+
# @param [Symbol] name The plugin to retrieve
|
97
|
+
#
|
98
|
+
# @return [Plugin]
|
99
|
+
#
|
100
|
+
# @api public
|
101
|
+
def [](name)
|
102
|
+
elements[name]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Assign a plugin to this environment registry
|
106
|
+
#
|
107
|
+
# @param [Symbol] name The registered plugin name
|
108
|
+
# @param [Module] mod The plugin to register
|
109
|
+
# @param [Hash] options optional configuration data
|
110
|
+
#
|
111
|
+
# @api private
|
112
|
+
def register(name, mod, options)
|
113
|
+
elements[name] = plugin_type.new(mod, options)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns plugin name by instance
|
117
|
+
#
|
118
|
+
# @return [Symbol] Plugin name
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
def plugin_name(plugin)
|
122
|
+
tuple = elements.find { |(_, p)| p.equal?(plugin) }
|
123
|
+
tuple[0] if tuple
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# A registry storing environment specific plugins
|
128
|
+
#
|
129
|
+
# @api private
|
130
|
+
class ConfigurationPluginRegistry < PluginRegistryBase
|
131
|
+
# @api private
|
132
|
+
def initialize(*args, **kwargs)
|
133
|
+
super(*args, **kwargs, plugin_type: ConfigurationPlugin)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return an environment plugin
|
137
|
+
#
|
138
|
+
# @param [Symbol] name The name of the environment plugin
|
139
|
+
#
|
140
|
+
# @raises [UnknownPluginError] if no plugin is found with the given name
|
141
|
+
#
|
142
|
+
# @api public
|
143
|
+
def fetch(name)
|
144
|
+
self[name] || raise(UnknownPluginError, name)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# A registry storing adapter specific plugins
|
149
|
+
#
|
150
|
+
# @api private
|
151
|
+
class AdapterPluginRegistry < PluginRegistryBase
|
152
|
+
option :plugin_type, default: -> { Plugin }
|
153
|
+
end
|
154
|
+
|
155
|
+
# Store a set of registries grouped by adapter
|
156
|
+
#
|
157
|
+
# @api private
|
158
|
+
class InternalPluginRegistry
|
159
|
+
# Return the existing registries
|
160
|
+
#
|
161
|
+
# @return [Hash]
|
162
|
+
#
|
163
|
+
# @api private
|
164
|
+
attr_reader :registries
|
165
|
+
|
166
|
+
# @api private
|
167
|
+
def initialize(plugin_type = Plugin)
|
168
|
+
@registries = Hash.new { |h, v| h[v] = AdapterPluginRegistry.new({}, plugin_type: plugin_type) }
|
169
|
+
end
|
170
|
+
|
171
|
+
# Return the plugin registry for a specific adapter
|
172
|
+
#
|
173
|
+
# @param [Symbol] name The name of the adapter
|
174
|
+
#
|
175
|
+
# @return [AdapterRegistry]
|
176
|
+
#
|
177
|
+
# @api private
|
178
|
+
def adapter(name)
|
179
|
+
registries[name]
|
180
|
+
end
|
181
|
+
|
182
|
+
# Return the plugin for a given adapter
|
183
|
+
#
|
184
|
+
# @param [Symbol] name The name of the plugin
|
185
|
+
# @param [Symbol] adapter_name (:default) The name of the adapter used
|
186
|
+
#
|
187
|
+
# @raises [UnknownPluginError] if no plugin is found with the given name
|
188
|
+
#
|
189
|
+
# @api public
|
190
|
+
def fetch(name, adapter_name = :default)
|
191
|
+
adapter(adapter_name)[name] || adapter(:default)[name] ||
|
192
|
+
raise(UnknownPluginError, name)
|
193
|
+
end
|
194
|
+
|
195
|
+
alias_method :[], :fetch
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ROM
|
2
|
+
module Plugins
|
3
|
+
module Command
|
4
|
+
# @api private
|
5
|
+
module Schema
|
6
|
+
def self.included(klass)
|
7
|
+
super
|
8
|
+
klass.extend(ClassInterface)
|
9
|
+
end
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
module ClassInterface
|
13
|
+
# @see Command.build
|
14
|
+
# @api public
|
15
|
+
def build(relation, options = {})
|
16
|
+
if options.key?(:input) || !relation.schema?
|
17
|
+
super
|
18
|
+
else
|
19
|
+
default_input = options.fetch(:input, input)
|
20
|
+
|
21
|
+
input_handler =
|
22
|
+
if default_input != Hash && relation.schema?
|
23
|
+
-> tuple { relation.input_schema[input[tuple]] }
|
24
|
+
elsif relation.schema?
|
25
|
+
relation.input_schema
|
26
|
+
else
|
27
|
+
default_input
|
28
|
+
end
|
29
|
+
|
30
|
+
super(relation, options.merge(input: input_handler))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rom/configuration_dsl'
|
2
|
+
require 'dry/core/deprecations'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module ConfigurationPlugins
|
6
|
+
# Provides macros for defining relations, mappers and commands
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
module ConfigurationDSL
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
def self.apply(configuration, options = {})
|
13
|
+
Dry::Core::Deprecations.announce(
|
14
|
+
:macros,
|
15
|
+
"Calling `use(:macros)` is no longer necessary. Macros are enabled by default.",
|
16
|
+
tag: :rom
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'dry/core/class_attributes'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Plugins
|
5
|
+
module Relation
|
6
|
+
# Experimental plugin for configuring relations with an external
|
7
|
+
# instrumentation system like dry-monitor or ActiveSupport::Notifications
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
module Instrumentation
|
11
|
+
extend Dry::Core::ClassAttributes
|
12
|
+
|
13
|
+
# This hooks sets up a relation class with injectible notifications object
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
def self.included(klass)
|
17
|
+
super
|
18
|
+
klass.option :notifications
|
19
|
+
klass.extend(ClassInterface)
|
20
|
+
klass.prepend(mixin)
|
21
|
+
klass.instrument(:to_a)
|
22
|
+
end
|
23
|
+
|
24
|
+
defines :mixin
|
25
|
+
mixin Module.new
|
26
|
+
|
27
|
+
module ClassInterface
|
28
|
+
def instrument(*methods)
|
29
|
+
(methods - Instrumentation.mixin.instance_methods).each do |meth|
|
30
|
+
Instrumentation.mixin.send(:define_method, meth) do
|
31
|
+
instrument { super() }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api public
|
38
|
+
def instrument(&block)
|
39
|
+
notifications.instrument(self.class.adapter, name: name.relation, **notification_payload(self), &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# @api private
|
45
|
+
def notification_payload(relation)
|
46
|
+
EMPTY_HASH
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'dry/core/cache'
|
2
|
+
require 'rom/constants'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module Plugins
|
6
|
+
module Relation
|
7
|
+
# Allows relations to access all other relations through registry
|
8
|
+
#
|
9
|
+
# For now this plugin is always enabled
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
class RegistryReader < Module
|
13
|
+
extend Dry::Core::Cache
|
14
|
+
|
15
|
+
EMPTY_REGISTRY = RelationRegistry.new(EMPTY_HASH).freeze
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
attr_reader :relations
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
def initialize(relations)
|
22
|
+
@relations = relations
|
23
|
+
define_readers!
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def included(klass)
|
28
|
+
super
|
29
|
+
return if klass.instance_methods.include?(:__registry__)
|
30
|
+
klass.option :__registry__, default: -> { EMPTY_REGISTRY }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
def define_readers!
|
37
|
+
relations.each do |name|
|
38
|
+
define_method(name) { __registry__[name] }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ROM
|
2
|
+
module Plugins
|
3
|
+
module Schema
|
4
|
+
# A plugin for automatically adding timestamp fields
|
5
|
+
# to the schema definition
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# schema do
|
9
|
+
# use :timestamps
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# # using non-default names
|
13
|
+
# schema do
|
14
|
+
# use :timestamps, attributes: %i(created_on updated_on)
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # using other types
|
18
|
+
# schema do
|
19
|
+
# use :timestamps, type: Types::Date
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
module Timestamps
|
24
|
+
DEFAULT_TIMESTAMPS = %i(created_at updated_at).freeze
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def self.apply(schema, options)
|
28
|
+
type = options.fetch(:type, Types::Time)
|
29
|
+
names = options.fetch(:attributes, DEFAULT_TIMESTAMPS)
|
30
|
+
attributes = names.map { |name| type.meta(name: name, source: schema.name) }
|
31
|
+
|
32
|
+
schema.attributes.concat(
|
33
|
+
schema.class.attributes(attributes, schema.attr_class)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
module DSL
|
39
|
+
# Sets non-default timestamp attributes
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# schema do
|
43
|
+
# use :timestamps
|
44
|
+
# timestamps :create_on, :updated_on
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def timestamps(*names)
|
49
|
+
options = plugin_options(:timestamps)
|
50
|
+
options[:attributes] = names unless names.empty?
|
51
|
+
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|