cuprum-collections 0.3.0 → 0.4.0

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/DEVELOPMENT.md +2 -2
  4. data/README.md +13 -11
  5. data/lib/cuprum/collections/association.rb +256 -0
  6. data/lib/cuprum/collections/associations/belongs_to.rb +32 -0
  7. data/lib/cuprum/collections/associations/has_many.rb +23 -0
  8. data/lib/cuprum/collections/associations/has_one.rb +23 -0
  9. data/lib/cuprum/collections/associations.rb +10 -0
  10. data/lib/cuprum/collections/basic/collection.rb +39 -74
  11. data/lib/cuprum/collections/basic/commands/find_many.rb +1 -1
  12. data/lib/cuprum/collections/basic/commands/find_matching.rb +1 -1
  13. data/lib/cuprum/collections/basic/repository.rb +9 -33
  14. data/lib/cuprum/collections/basic.rb +1 -0
  15. data/lib/cuprum/collections/collection.rb +154 -0
  16. data/lib/cuprum/collections/commands/associations/find_many.rb +161 -0
  17. data/lib/cuprum/collections/commands/associations/require_many.rb +48 -0
  18. data/lib/cuprum/collections/commands/associations.rb +13 -0
  19. data/lib/cuprum/collections/commands/find_one_matching.rb +1 -1
  20. data/lib/cuprum/collections/commands.rb +1 -0
  21. data/lib/cuprum/collections/errors/abstract_find_error.rb +1 -1
  22. data/lib/cuprum/collections/relation.rb +401 -0
  23. data/lib/cuprum/collections/repository.rb +71 -4
  24. data/lib/cuprum/collections/resource.rb +65 -0
  25. data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +2137 -0
  26. data/lib/cuprum/collections/rspec/contracts/basic/command_contracts.rb +484 -0
  27. data/lib/cuprum/collections/rspec/contracts/basic.rb +11 -0
  28. data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +429 -0
  29. data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +1462 -0
  30. data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +1093 -0
  31. data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +1381 -0
  32. data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +605 -0
  33. data/lib/cuprum/collections/rspec/contracts.rb +23 -0
  34. data/lib/cuprum/collections/rspec/fixtures.rb +85 -82
  35. data/lib/cuprum/collections/rspec.rb +4 -1
  36. data/lib/cuprum/collections/version.rb +1 -1
  37. data/lib/cuprum/collections.rb +9 -4
  38. metadata +23 -19
  39. data/lib/cuprum/collections/base.rb +0 -11
  40. data/lib/cuprum/collections/basic/rspec/command_contract.rb +0 -392
  41. data/lib/cuprum/collections/rspec/assign_one_command_contract.rb +0 -168
  42. data/lib/cuprum/collections/rspec/build_one_command_contract.rb +0 -93
  43. data/lib/cuprum/collections/rspec/collection_contract.rb +0 -190
  44. data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +0 -108
  45. data/lib/cuprum/collections/rspec/find_many_command_contract.rb +0 -407
  46. data/lib/cuprum/collections/rspec/find_matching_command_contract.rb +0 -194
  47. data/lib/cuprum/collections/rspec/find_one_command_contract.rb +0 -157
  48. data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +0 -84
  49. data/lib/cuprum/collections/rspec/query_builder_contract.rb +0 -92
  50. data/lib/cuprum/collections/rspec/query_contract.rb +0 -650
  51. data/lib/cuprum/collections/rspec/querying_contract.rb +0 -298
  52. data/lib/cuprum/collections/rspec/repository_contract.rb +0 -235
  53. data/lib/cuprum/collections/rspec/update_one_command_contract.rb +0 -80
  54. data/lib/cuprum/collections/rspec/validate_one_command_contract.rb +0 -96
@@ -0,0 +1,401 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ require 'cuprum/collections'
6
+
7
+ module Cuprum::Collections
8
+ # Abstract class representing a group or view of entities.
9
+ class Relation
10
+ # Methods for resolving a singular or plural relation.
11
+ module Cardinality
12
+ # @return [Boolean] true if the relation is plural; otherwise false.
13
+ def plural?
14
+ @plural
15
+ end
16
+
17
+ # @return [Boolean] true if the relation is singular; otherwise false.
18
+ def singular?
19
+ !@plural
20
+ end
21
+
22
+ private
23
+
24
+ def resolve_plurality(**params) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
25
+ if params.key?(:plural) && !params[:plural].nil?
26
+ if params.key?(:singular) && !params[:singular].nil?
27
+ message =
28
+ 'ambiguous cardinality: initialized with parameters ' \
29
+ "plural: #{params[:plural].inspect} and singular: " \
30
+ "#{params[:singular].inspect}"
31
+
32
+ raise ArgumentError, message
33
+ end
34
+
35
+ validate_cardinality(params[:plural], as: 'plural')
36
+
37
+ return params[:plural]
38
+ end
39
+
40
+ if params.key?(:singular) && !params[:singular].nil?
41
+ validate_cardinality(params[:singular], as: 'singular')
42
+
43
+ return !params[:singular]
44
+ end
45
+
46
+ true
47
+ end
48
+
49
+ def validate_cardinality(value, as:)
50
+ return if value == true || value == false # rubocop:disable Style/MultipleComparison
51
+
52
+ raise ArgumentError, "#{as} must be true or false"
53
+ end
54
+ end
55
+
56
+ # Methods for disambiguating parameters with multiple keywords.
57
+ module Disambiguation
58
+ class << self
59
+ # Helper method for resolving an ambiguous keyword.
60
+ #
61
+ # @param params [Hash] the original method keywords.
62
+ # @param key [Symbol] the original key to resolve.
63
+ # @param alternatives [Symbol, Array<Symbol>] the additional keywords.
64
+ #
65
+ # @return [Hash] the disambiguated keywords.
66
+ def disambiguate_keyword(params, key, *alternatives) # rubocop:disable Metrics/MethodLength
67
+ params = params.dup
68
+ values = keyword_values(params, key, *alternatives)
69
+
70
+ return params if values.empty?
71
+
72
+ if values.size == 1
73
+ match, value = values.first
74
+
75
+ unless match == key
76
+ tools.core_tools.deprecate(
77
+ "#{match.inspect} keyword",
78
+ message: "Use #{key.inspect} instead"
79
+ )
80
+ end
81
+
82
+ return params.merge(key => value)
83
+ end
84
+
85
+ raise ArgumentError, ambiguous_keywords_error(values)
86
+ end
87
+
88
+ # Helper method for resolving a Relation's required parameters.
89
+ #
90
+ # The returned Hash will define the :entity_class, :singular_name,
91
+ # :name, and :qualified_name keys.
92
+ #
93
+ # @param params [Hash] the parameters to resolve.
94
+ # @param ambiguous [Hash{Symbol => Symbol, Array<Symbol>}] ambiguous
95
+ # keywords to resolve. Each key-value pair is passed to
96
+ # .disambiguate_keyword before the parameters are resolved.
97
+ #
98
+ # @return [Hash] the resolved parameters.
99
+ #
100
+ # @see .disambiguate_keyword
101
+ # @see Cuprum::Collections::Relation::Parameters.resolve_parameters
102
+ def resolve_parameters(params, **ambiguous)
103
+ params = ambiguous.reduce(params) do |hsh, (key, alternatives)|
104
+ disambiguate_keyword(hsh, key, *alternatives)
105
+ end
106
+
107
+ Cuprum::Collections::Relation::Parameters.resolve_parameters(params)
108
+ end
109
+
110
+ private
111
+
112
+ def ambiguous_keywords_error(values)
113
+ expected, _ = values.first
114
+ formatted =
115
+ values
116
+ .map { |key, value| "#{key}: #{value.inspect}" }
117
+ .join(', ')
118
+
119
+ "ambiguous parameter #{expected}: initialized with parameters " \
120
+ "#{formatted}"
121
+ end
122
+
123
+ def keyword_values(keywords, *keys)
124
+ keys
125
+ .map { |key| [key, keywords.delete(key)] }
126
+ .reject { |_, value| value.nil? } # rubocop:disable Style/CollectionCompact
127
+ end
128
+
129
+ def tools
130
+ SleepingKingStudios::Tools::Toolbelt.instance
131
+ end
132
+ end
133
+
134
+ # (see Cuprum::Collections::Relation::Disambiguation.disambiguate_keyword)
135
+ def disambiguate_keyword(params, key, *alternatives)
136
+ Disambiguation.disambiguate_keyword(params, key, *alternatives)
137
+ end
138
+
139
+ # (see Cuprum::Collections::Relation::Disambiguation.resolve_parameters)
140
+ def resolve_parameters(params, **ambiguous)
141
+ Disambiguation.resolve_parameters(params, **ambiguous)
142
+ end
143
+ end
144
+
145
+ # Methods for resolving a relations's naming and entity class from options.
146
+ module Parameters # rubocop:disable Metrics/ModuleLength
147
+ PARAMETER_KEYS = %i[entity_class name qualified_name].freeze
148
+ private_constant :PARAMETER_KEYS
149
+
150
+ class << self
151
+ # @overload resolve_parameters(entity_class: nil, singular_name: nil, name: nil, qualified_name: nil)
152
+ # Helper method for resolving a Relation's required parameters.
153
+ #
154
+ # The returned Hash will define the :entity_class, :singular_name,
155
+ # :name, and :qualified_name keys.
156
+ #
157
+ # @param entity_class [Class, String] the class of entity represented
158
+ # by the relation.
159
+ # @param singular_name [String] the name of an entity in the relation.
160
+ # @param name [String] the name of the relation.
161
+ # @param qualified_name [String] a scoped name for the relation.
162
+ #
163
+ # @return [Hash] the resolved parameters.
164
+ def resolve_parameters(params) # rubocop:disable Metrics/MethodLength
165
+ validate_parameters(**params)
166
+
167
+ entity_class = entity_class_from(**params)
168
+ class_name = entity_class_name(entity_class)
169
+ name = relation_name_from(**params, class_name: class_name)
170
+ plural_name = plural_name_from(**params, name: name)
171
+ qualified_name = qualified_name_from(**params, class_name: class_name)
172
+ singular_name = singular_name_from(**params, name: name)
173
+
174
+ {
175
+ entity_class: entity_class,
176
+ name: name,
177
+ plural_name: plural_name,
178
+ qualified_name: qualified_name,
179
+ singular_name: singular_name
180
+ }
181
+ end
182
+
183
+ private
184
+
185
+ def classify(raw)
186
+ raw
187
+ .then { |str| tools.string_tools.singularize(str).to_s }
188
+ .split('/')
189
+ .map { |str| tools.string_tools.camelize(str) }
190
+ .join('::')
191
+ end
192
+
193
+ def entity_class_from(**params)
194
+ if has_key?(params, :entity_class)
195
+ entity_class = params[:entity_class]
196
+
197
+ return entity_class.is_a?(Class) ? entity_class : entity_class.to_s
198
+ end
199
+
200
+ if has_key?(params, :qualified_name)
201
+ return classify(params[:qualified_name])
202
+ end
203
+
204
+ classify(params[:name])
205
+ end
206
+
207
+ def entity_class_name(entity_class, scoped: true)
208
+ (entity_class.is_a?(Class) ? entity_class.name : entity_class)
209
+ .split('::')
210
+ .map { |str| tools.string_tools.underscore(str) }
211
+ .then { |ary| scoped ? ary.join('/') : ary.last }
212
+ end
213
+
214
+ def has_key?(params, key) # rubocop:disable Naming/PredicateName
215
+ return false unless params.key?(key)
216
+
217
+ !params[key].nil?
218
+ end
219
+
220
+ def plural_name_from(name:, **parameters)
221
+ if parameters.key?(:plural_name) && !parameters[:plural_name].nil?
222
+ return validate_parameter(
223
+ parameters[:plural_name],
224
+ as: 'plural name'
225
+ )
226
+ end
227
+
228
+ tools.string_tools.pluralize(name)
229
+ end
230
+
231
+ def qualified_name_from(class_name:, **params)
232
+ if has_key?(params, :qualified_name)
233
+ return params[:qualified_name].to_s
234
+ end
235
+
236
+ tools.string_tools.pluralize(class_name)
237
+ end
238
+
239
+ def relation_name_from(class_name:, **params)
240
+ return params[:name].to_s if has_key?(params, :name)
241
+
242
+ tools.string_tools.pluralize(class_name.split('/').last)
243
+ end
244
+
245
+ def singular_name_from(name:, **parameters)
246
+ if parameters.key?(:singular_name) && !parameters[:singular_name].nil?
247
+ return validate_parameter(
248
+ parameters[:singular_name],
249
+ as: 'singular name'
250
+ )
251
+ end
252
+
253
+ tools.string_tools.singularize(name)
254
+ end
255
+
256
+ def tools
257
+ SleepingKingStudios::Tools::Toolbelt.instance
258
+ end
259
+
260
+ def validate_entity_class(value)
261
+ return if value.is_a?(Class)
262
+
263
+ if value.nil? || value.is_a?(String) || value.is_a?(Symbol)
264
+ tools.assertions.validate_name(value, as: 'entity class')
265
+
266
+ return
267
+ end
268
+
269
+ raise ArgumentError,
270
+ 'entity class is not a Class, a String or a Symbol'
271
+ end
272
+
273
+ def validate_parameter(value, as:)
274
+ tools.assertions.validate_name(value, as: as)
275
+
276
+ value.to_s
277
+ end
278
+
279
+ def validate_parameter_keys(params)
280
+ return if PARAMETER_KEYS.any? { |key| has_key?(params, key) }
281
+
282
+ raise ArgumentError, "name or entity class can't be blank"
283
+ end
284
+
285
+ def validate_parameters(**params) # rubocop:disable Metrics/MethodLength
286
+ validate_parameter_keys(params)
287
+
288
+ if has_key?(params, :entity_class)
289
+ validate_entity_class(params[:entity_class])
290
+ end
291
+
292
+ if has_key?(params, :name)
293
+ validate_parameter(params[:name], as: 'name')
294
+ end
295
+
296
+ if has_key?(params, :plural_name)
297
+ validate_parameter(params[:plural_name], as: 'plural name')
298
+ end
299
+
300
+ if has_key?(params, :qualified_name)
301
+ validate_parameter(params[:qualified_name], as: 'qualified name')
302
+ end
303
+
304
+ if has_key?(params, :singular_name) # rubocop:disable Style/GuardClause
305
+ validate_parameter(params[:singular_name], as: 'singular name')
306
+ end
307
+ end
308
+ end
309
+
310
+ # @return [String] the name of the relation.
311
+ attr_reader :name
312
+
313
+ # @return [String] the pluralized name of the relation.
314
+ attr_reader :plural_name
315
+
316
+ # @return [String] a scoped name for the relation.
317
+ attr_reader :qualified_name
318
+
319
+ # @return [String] the name of an entity in the relation.
320
+ attr_reader :singular_name
321
+
322
+ # @return [Class] the class of entity represented by the relation.
323
+ def entity_class
324
+ return @entity_class if @entity_class.is_a?(Class)
325
+
326
+ @entity_class = Object.const_get(@entity_class)
327
+ end
328
+
329
+ # (see Cuprum::Collections::Relation::Parameters.resolve_parameters)
330
+ def resolve_parameters(parameters)
331
+ Parameters.resolve_parameters(parameters)
332
+ end
333
+ end
334
+
335
+ # Methods for specifying a relation's primary key.
336
+ module PrimaryKeys
337
+ # @return [String] the name of the primary key attribute. Defaults to
338
+ # 'id'.
339
+ def primary_key_name
340
+ @primary_key_name ||= options.fetch(:primary_key_name, 'id').to_s
341
+ end
342
+
343
+ # @return [Class, Stannum::Constraint] the type of the primary key
344
+ # attribute. Defaults to Integer.
345
+ def primary_key_type
346
+ @primary_key_type ||=
347
+ options
348
+ .fetch(:primary_key_type, Integer)
349
+ .then { |obj| obj.is_a?(String) ? Object.const_get(obj) : obj }
350
+ end
351
+ end
352
+
353
+ IGNORED_PARAMETERS = %i[
354
+ entity_class
355
+ name
356
+ qualified_name
357
+ singular_name
358
+ ].freeze
359
+ private_constant :IGNORED_PARAMETERS
360
+
361
+ include Cuprum::Collections::Relation::Parameters
362
+
363
+ # @overload initialize(entity_class: nil, name: nil, qualified_name: nil, singular_name: nil, **options)
364
+ # @param entity_class [Class, String] the class of entity represented by
365
+ # the relation.
366
+ # @param name [String] the name of the relation.
367
+ # @param qualified_name [String] a scoped name for the relation.
368
+ # @param singular_name [String] the name of an entity in the relation.
369
+ # @param options [Hash] additional options for the relation.
370
+ def initialize(**parameters)
371
+ relation_params = resolve_parameters(parameters)
372
+
373
+ @entity_class = relation_params[:entity_class]
374
+ @name = relation_params[:name]
375
+ @plural_name = relation_params[:plural_name]
376
+ @qualified_name = relation_params[:qualified_name]
377
+ @singular_name = relation_params[:singular_name]
378
+
379
+ @options = ignore_parameters(**parameters)
380
+ end
381
+
382
+ # @return [Hash] additional options for the relation.
383
+ attr_reader :options
384
+
385
+ private
386
+
387
+ def ignore_parameters(**parameters)
388
+ parameters
389
+ .reject { |key, _| ignored_parameters.include?(key) }
390
+ .to_h
391
+ end
392
+
393
+ def ignored_parameters
394
+ @ignored_parameters ||= Set.new(IGNORED_PARAMETERS)
395
+ end
396
+
397
+ def tools
398
+ SleepingKingStudios::Tools::Toolbelt.instance
399
+ end
400
+ end
401
+ end
@@ -3,6 +3,7 @@
3
3
  require 'forwardable'
4
4
 
5
5
  require 'cuprum/collections'
6
+ require 'cuprum/collections/relation'
6
7
 
7
8
  module Cuprum::Collections
8
9
  # A repository represents a group of collections.
@@ -16,6 +17,9 @@ module Cuprum::Collections
16
17
  class Repository
17
18
  extend Forwardable
18
19
 
20
+ # Error raised when trying to call an abstract repository method.
21
+ class AbstractRepositoryError < StandardError; end
22
+
19
23
  # Error raised when trying to add an existing collection to the repository.
20
24
  class DuplicateCollectionError < StandardError; end
21
25
 
@@ -57,12 +61,12 @@ module Cuprum::Collections
57
61
  # The collection must implement the #collection_name property. Repository
58
62
  # subclasses may enforce additional requirements.
59
63
  #
60
- # @param collection [#collection_name] The collection to add to the
61
- # repository.
62
- # @param force [true, false] If true, override an existing collection with
64
+ # @param collection [Cuprum::Collections::Collection] the collection to add
65
+ # to the repository.
66
+ # @param force [true, false] if true, override an existing collection with
63
67
  # the same name.
64
68
  #
65
- # @return [Cuprum::Rails::Repository] the repository.
69
+ # @return [Cuprum::Collections::Repository] the repository.
66
70
  #
67
71
  # @raise [DuplicateCollectionError] if a collection with the same name
68
72
  # already exists in the repository.
@@ -80,6 +84,57 @@ module Cuprum::Collections
80
84
  end
81
85
  alias << add
82
86
 
87
+ # @overload create(collection_name: nil, entity_class: nil, force: false, **options)
88
+ # Adds a new collection with the given name to the repository.
89
+ #
90
+ # @param collection_name [String] the name of the new collection.
91
+ # @param entity_class [Class, String] the class of entity represented in
92
+ # the collection.
93
+ # @param force [true, false] if true, override an existing collection with
94
+ # the same name.
95
+ # @param options [Hash] additional options to pass to Collection.new.
96
+ #
97
+ # @return [Cuprum::Collections::Collection] the created collection.
98
+ #
99
+ # @raise [DuplicateCollectionError] if a collection with the same name
100
+ # already exists in the repository.
101
+ def create(force: false, **options)
102
+ collection = build_collection(**options)
103
+
104
+ add(collection, force: force)
105
+
106
+ collection
107
+ end
108
+
109
+ # @overload find_or_create(collection_name: nil, entity_class: nil, **options)
110
+ # Finds or creates a new collection with the given name.
111
+ #
112
+ # @param collection_name [String] the name of the new collection.
113
+ # @param entity_class [Class, String] the class of entity represented in
114
+ # the collection.
115
+ # @param options [Hash] additional options to pass to Collection.new.
116
+ #
117
+ # @return [Cuprum::Collections::Collection] the created collection.
118
+ #
119
+ # @raise [DuplicateCollectionError] if a collection with the same name
120
+ # but different parameters already exists in the repository.
121
+ def find_or_create(**parameters)
122
+ qualified_name = qualified_name_for(**parameters)
123
+
124
+ unless key?(qualified_name)
125
+ create(**parameters)
126
+
127
+ return @collections[qualified_name]
128
+ end
129
+
130
+ collection = @collections[qualified_name]
131
+
132
+ return collection if collection.matches?(**parameters)
133
+
134
+ raise DuplicateCollectionError,
135
+ "collection #{qualified_name} already exists"
136
+ end
137
+
83
138
  # Checks if a collection with the given name exists in the repository.
84
139
  #
85
140
  # @param qualified_name [String, Symbol] The name to check for.
@@ -91,6 +146,18 @@ module Cuprum::Collections
91
146
 
92
147
  private
93
148
 
149
+ def build_collection(**)
150
+ raise AbstractRepositoryError,
151
+ "#{self.class.name} is an abstract class. Define a repository " \
152
+ 'subclass and implement the #build_collection method.'
153
+ end
154
+
155
+ def qualified_name_for(**parameters)
156
+ Cuprum::Collections::Relation::Disambiguation
157
+ .resolve_parameters(parameters, name: :collection_name)
158
+ .fetch(:qualified_name)
159
+ end
160
+
94
161
  def valid_collection?(collection)
95
162
  collection.respond_to?(:collection_name)
96
163
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections'
4
+ require 'cuprum/collections/relation'
5
+
6
+ module Cuprum::Collections
7
+ # Class representing a singular or plural resource of entities.
8
+ class Resource < Cuprum::Collections::Relation
9
+ include Cuprum::Collections::Relation::Cardinality
10
+ include Cuprum::Collections::Relation::Disambiguation
11
+ include Cuprum::Collections::Relation::PrimaryKeys
12
+
13
+ # @overload initialize(entity_class: nil, name: nil, qualified_name: nil, singular_name: nil, **options)
14
+ # @param entity_class [Class, String] the class of entity represented by
15
+ # the resource.
16
+ # @param name [String] the name of the resource. Aliased as
17
+ # :resource_name.
18
+ # @param qualified_name [String] a scoped name for the resource.
19
+ # @param singular_name [String] the name of an entity in the resource.
20
+ # @param options [Hash] additional options for the resource.
21
+ #
22
+ # @option options plural [Boolean] if true, the resource represents a
23
+ # plural resource. Defaults to true. Can also be specified as :singular.
24
+ # @option options primary_key_name [String] the name of the primary key
25
+ # attribute. Defaults to 'id'.
26
+ # @option primary_key_type [Class, Stannum::Constraint] the type of
27
+ # the primary key attribute. Defaults to Integer.
28
+ def initialize(**params)
29
+ params = disambiguate_keyword(params, :entity_class, :resource_class)
30
+ params = disambiguate_keyword(params, :name, :resource_name)
31
+ params = disambiguate_keyword(
32
+ params,
33
+ :singular_name,
34
+ :singular_resource_name
35
+ )
36
+ @plural = resolve_plurality(**params)
37
+
38
+ super(**params)
39
+ end
40
+
41
+ # @return [Class] the class of entity represented by the resource.
42
+ def resource_class
43
+ tools.core_tools.deprecate '#resource_class method',
44
+ message: 'Use #entity_class instead'
45
+
46
+ entity_class
47
+ end
48
+
49
+ # @return [String] the name of the resource.
50
+ def resource_name
51
+ tools.core_tools.deprecate '#resource_name method',
52
+ message: 'Use #name instead'
53
+
54
+ name
55
+ end
56
+
57
+ # @return[String] the name of an entity in the resource.
58
+ def singular_resource_name
59
+ tools.core_tools.deprecate '#singular_resource_name method',
60
+ message: 'Use #singular_name instead'
61
+
62
+ singular_name
63
+ end
64
+ end
65
+ end