object_identifier 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0a0e09332282b492a3c9e83f9ab59a319a421c9ed3e83c2bfa87f6bfe20e6bd
4
- data.tar.gz: 7b27cf091a8ecfd1c747fb75918f4b88aabd725dba3221489021aa2f5d24138a
3
+ metadata.gz: 4553678db77484aa04ce8bf00e3238310bb253632fb8867cae4e948a35bfda6c
4
+ data.tar.gz: afae645239815d3a9a011b56892127eccbf0dbc9558fc59ed6d7c15349fdbbe7
5
5
  SHA512:
6
- metadata.gz: 6b1150c07800795094a4f15e475ba180187c51e248f0a5cfb385030b9720c4b2e3000692974f89eecc211b223778159b3041b358957265ae7e2e55b2835f8e47
7
- data.tar.gz: 75b8bc577271cfe6b8a58ec5ec8a7d65c1e308aee3dfef8481e65869ac4e749ff9725f7f0d4fa752b391638c0e4b0003cafd2cd91ff352514fa03301df7931e8
6
+ metadata.gz: 639af898d48d62cfdf69c325986fab12147ddad81219b0e60557a9e52288597d5dddd3f4473ac94df3bbfd5ade304bb55c3f1a49b9918f4c959941ba4899f773
7
+ data.tar.gz: 9f715f65e2afa4ac783db81cd8cab09b137b206dae15d4b05e757dc2d0c82e04848dbd2551e02b8a7c6127aed3b5cb5257c920e8d79f027cf42d1b61ae238679
@@ -0,0 +1,38 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ "master" ]
13
+ pull_request:
14
+ branches: [ "master" ]
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+ runs-on: ubuntu-latest
22
+ strategy:
23
+ matrix:
24
+ ruby-version: ['2.7', '3.0', '3.1', '3.2']
25
+
26
+ steps:
27
+ - uses: actions/checkout@v3
28
+ - name: Set up Ruby
29
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
30
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
31
+ # uses: ruby/setup-ruby@v1
32
+ uses: ruby/setup-ruby@ee2113536afb7f793eed4ce60e8d3b26db912da4 # v1.127.0
33
+ with:
34
+ ruby-version: ${{ matrix.ruby-version }}
35
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
36
+
37
+ - name: Run tests
38
+ run: bundle exec rake
data/.rubocop.yml CHANGED
@@ -24,6 +24,18 @@ Layout/FirstHashElementIndentation:
24
24
  Layout/FirstParameterIndentation:
25
25
  Enabled: false # Revisit if more settings become available.
26
26
 
27
+ Layout/LineContinuationSpacing:
28
+ EnforcedStyle: no_space
29
+
30
+ Layout/LineEndStringConcatenationIndentation:
31
+ EnforcedStyle: aligned
32
+
33
+ Layout/LineLength:
34
+ Max: 80
35
+ Exclude:
36
+ - "object_identifier.gemspec"
37
+ - "scripts/benchmarking/**/*"
38
+
27
39
  Layout/MultilineMethodCallBraceLayout:
28
40
  EnforcedStyle: same_line
29
41
 
@@ -42,11 +54,15 @@ Lint/AmbiguousOperator:
42
54
  Lint/AmbiguousRegexpLiteral:
43
55
  Enabled: false # Conflicts with other rules.
44
56
 
57
+ Lint/OrAssignmentToConstant:
58
+ Exclude:
59
+ - "scripts/**/*"
60
+
45
61
  Lint/Void:
46
62
  CheckForMethodsWithNoSideEffects: true
47
63
 
48
64
  Metrics/BlockLength:
49
- ExcludedMethods:
65
+ AllowedMethods:
50
66
  - describe
51
67
  - context
52
68
  - ips # Benchmarking
@@ -55,11 +71,6 @@ Metrics/ClassLength:
55
71
  Exclude:
56
72
  - "test/**/*"
57
73
 
58
- Metrics/LineLength:
59
- Max: 80
60
- Exclude:
61
- - "object_identifier.gemspec"
62
-
63
74
  Naming/MethodParameterName:
64
75
  AllowedNames:
65
76
  - a
@@ -71,6 +82,10 @@ Style/Alias:
71
82
  Style/BlockDelimiters:
72
83
  Enabled: false # Reconsider later.
73
84
 
85
+ Style/ClassAndModuleChildren:
86
+ AutoCorrect: true
87
+ EnforcedStyle: compact
88
+
74
89
  Style/EmptyElse:
75
90
  # It"s helpful to show intent by including a comment in an else block.
76
91
  Enabled: false
@@ -88,6 +103,13 @@ Style/FormatString:
88
103
  Style/Lambda:
89
104
  EnforcedStyle: literal
90
105
 
106
+ Style/LambdaCall:
107
+ Enabled: false # Allow ServiceObject.(*). Only use on classes, not instances.
108
+
109
+ Style/OpenStructUse:
110
+ Exclude:
111
+ - "test/**/*"
112
+
91
113
  Style/RegexpLiteral:
92
114
  EnforcedStyle: mixed
93
115
 
data/CHANGELOG.md CHANGED
@@ -1,4 +1,9 @@
1
- ### 0.4.1 - 2022-12-?
1
+ ### 0.5.0 - 2023-01-04
2
+ - Add support for defining customer Formatters.
3
+ - Add ObjectInspector::Configuration#formatter_class setting for overriding the default Formatter. See the README for more.
4
+ - Add a benchmarking script for comparing performance of formatters. See the README for more.
5
+
6
+ ### 0.4.1 - 2022-12-30
2
7
  - Make compatible with Ruby 3.2 (and likely Ruby 3.0 and 3.1 as well).
3
8
  - Update development dependencies.
4
9
 
data/Gemfile.lock CHANGED
@@ -1,13 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- object_identifier (0.4.1)
4
+ object_identifier (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ansi (1.5.0)
10
10
  ast (2.4.2)
11
+ benchmark-ips (2.10.0)
11
12
  builder (3.2.4)
12
13
  byebug (11.1.3)
13
14
  coderay (1.1.3)
@@ -15,12 +16,13 @@ GEM
15
16
  json (2.6.3)
16
17
  kwalify (0.7.2)
17
18
  method_source (1.0.0)
18
- minitest (5.16.3)
19
+ minitest (5.17.0)
19
20
  minitest-reporters (1.5.0)
20
21
  ansi
21
22
  builder
22
23
  minitest (>= 5.0)
23
24
  ruby-progressbar
25
+ much-stub (0.1.10)
24
26
  parallel (1.22.1)
25
27
  parser (3.1.3.0)
26
28
  ast (~> 2.4.1)
@@ -38,14 +40,14 @@ GEM
38
40
  rainbow (>= 2.0, < 4.0)
39
41
  regexp_parser (2.6.1)
40
42
  rexml (3.2.5)
41
- rubocop (1.41.1)
43
+ rubocop (1.42.0)
42
44
  json (~> 2.3)
43
45
  parallel (~> 1.10)
44
46
  parser (>= 3.1.2.1)
45
47
  rainbow (>= 2.2.2, < 4.0)
46
48
  regexp_parser (>= 1.8, < 3.0)
47
49
  rexml (>= 3.2.5, < 4.0)
48
- rubocop-ast (>= 1.23.0, < 2.0)
50
+ rubocop-ast (>= 1.24.1, < 2.0)
49
51
  ruby-progressbar (~> 1.7)
50
52
  unicode-display_width (>= 1.4.0, < 3.0)
51
53
  rubocop-ast (1.24.1)
@@ -63,10 +65,12 @@ PLATFORMS
63
65
  ruby
64
66
 
65
67
  DEPENDENCIES
68
+ benchmark-ips
66
69
  bundler
67
70
  byebug
68
71
  minitest
69
72
  minitest-reporters
73
+ much-stub
70
74
  object_identifier!
71
75
  pry
72
76
  pry-byebug
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Object Identifier
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/object_identifier.svg)](https://badge.fury.io/rb/object_identifier)
4
- [![Test Coverage](https://api.codeclimate.com/v1/badges/0b737a72d16ec755c1ff/test_coverage)](https://codeclimate.com/github/pdobb/object_identifier/test_coverage)
5
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/0b737a72d16ec755c1ff/maintainability)](https://codeclimate.com/github/pdobb/object_identifier/maintainability)
6
5
 
7
6
  Object Identifier allows quick, easy, and uniform identification of an object by inspecting its class name and outputting any desirable attributes/methods. It is great for logging, sending descriptive notification messages, etc.
@@ -45,6 +44,21 @@ Tested MRI Ruby Versions:
45
44
  * 2.6.6
46
45
 
47
46
 
47
+ ## Configuration
48
+
49
+ Global/default values for ObjectIdentifier can be configured via the ObjectIdentifier::Configuration object.
50
+
51
+ _Note: In a Rails app, the following would go in e.g. `config/initializers/object_identifier.rb`_
52
+
53
+ ```ruby
54
+ # Default values are shown.
55
+ ObjectIdentifier.configure do |config|
56
+ config.formatter_class = ObjectIdentifier::StringFormatter
57
+ config.default_attributes = %i[id]
58
+ end
59
+ ```
60
+
61
+
48
62
  ## Usage
49
63
 
50
64
  ### Defaults
@@ -152,6 +166,23 @@ OpenStruct.new(my_value: my_value_object).identify(:my_value)
152
166
  ObjectIdentifier works great with the [ObjectInspector](https://github.com/pdobb/object_inspector) gem.
153
167
 
154
168
 
169
+ ### Benchmarking Formatters
170
+
171
+ Performance of Formatters can be tested by playing the [Formatters Benchmarking Scripts](https://github.com/pdobb/object_identifier/tree/master/scripts/benchmarking) in the pry console for this gem.
172
+
173
+ Custom Formatters may be similarly gauged for comparison by adding them to the `custom_formatter_klasses` array before playing the script.
174
+
175
+ ```ruby
176
+ custom_formatter_klasses = [MyCustomFormatter]
177
+
178
+ play scripts/benchmarking/formatters.rb
179
+ # ObjectIdentifier::StringFormatter
180
+ # 58.478k (± 0.8%) i/s - 295.776k in 5.058178s
181
+ # MyCustomFormatter
182
+ # ...
183
+ ```
184
+
185
+
155
186
  ## Development
156
187
 
157
188
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -40,6 +40,6 @@ class Object
40
40
  # (1..10).to_a.identify(:to_f, limit: 2)
41
41
  # # => "Integer[to_f:1.0], Integer[to_f:2.0], ... (8 more)"
42
42
  def identify(*args, **kargs)
43
- ObjectIdentifier::Identifier.identify(self, *args, **kargs)
43
+ ObjectIdentifier::Identifier.(self, *args, **kargs)
44
44
  end
45
45
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ObjectIdentifier::StringFormatter builds a String to identify the
4
+ # given object(s).
5
+ class ObjectIdentifier::StringFormatter
6
+ NO_OBJECTS_INDICATOR = "[no objects]"
7
+ KLASS_NOT_GIVEN = "NOT_GIVEN"
8
+
9
+ def self.call(objects, *attributes, **kargs)
10
+ new(objects, *attributes, **kargs).call
11
+ end
12
+
13
+ # @param objects [Object, [Object, ...]] the object(s) to be interrogated for
14
+ # String values to be added to the output String
15
+ # @param attributes [Array, *args] a list of method calls to interrogate the
16
+ # given object(s) with
17
+ # @param limit [Integer, nil] a given limit on the number of objects to
18
+ # interrogate
19
+ # @param klass [String, Symbol] a preferred type name for identifying the
20
+ # given object(s) as
21
+ def initialize(
22
+ objects,
23
+ attributes = ObjectIdentifier::Identifier.default_attributes,
24
+ limit: nil,
25
+ klass: KLASS_NOT_GIVEN)
26
+ @objects = ObjectIdentifier::ArrayWrap.(objects)
27
+ @attributes = ObjectIdentifier::ArrayWrap.(attributes)
28
+ @limit = (limit || @objects.size).to_i
29
+ @klass = klass.to_s
30
+ end
31
+
32
+ # Output the self-identifying string for the given object(s). Will either
33
+ # return a single object representation or a list of object
34
+ # representations, based on the number of objects we're identifying.
35
+ #
36
+ # @return [String] a string that identifies the object(s)
37
+ def call
38
+ return NO_OBJECTS_INDICATOR if @objects.empty?
39
+
40
+ output_strings = @objects.first(@limit).map { |obj| format(obj) }
41
+ output_strings << "... (#{truncated_objects_count} more)" if truncated?
42
+ output_strings.join(", ")
43
+ end
44
+
45
+ private
46
+
47
+ def format(object)
48
+ return NO_OBJECTS_INDICATOR if blank?(object)
49
+
50
+ "#{class_name(object)}[#{format_attributes(evaluate_attributes(object))}]"
51
+ end
52
+
53
+ # Simple version of Rails' Object#blank? method.
54
+ def blank?(object)
55
+ object.nil? || object == [] || object == {}
56
+ end
57
+
58
+ def class_name(object)
59
+ klass_given? ? @klass : object.class.name
60
+ end
61
+
62
+ def klass_given?
63
+ @klass != KLASS_NOT_GIVEN
64
+ end
65
+
66
+ def format_attributes(attributes_hash)
67
+ return if attributes_hash.empty?
68
+
69
+ attributes_formatter = determine_attributes_formatter(attributes_hash)
70
+ attributes_hash.map(&attributes_formatter).join(", ")
71
+ end
72
+
73
+ def determine_attributes_formatter(attributes_hash)
74
+ if attributes_hash.one?
75
+ ->(_key, value) { value.inspect_lit }
76
+ else
77
+ ->(key, value) { "#{key}:#{value.inspect_lit}" }
78
+ end
79
+ end
80
+
81
+ # @return [Hash]
82
+ def evaluate_attributes(object)
83
+ @attributes.each_with_object({}) { |key, acc|
84
+ if object.respond_to?(key, :include_private)
85
+ acc[key] = object.send(key)
86
+ elsif key.to_s.start_with?("@")
87
+ acc[key] = object.instance_variable_get(key)
88
+ end
89
+ }
90
+ end
91
+
92
+ def truncated_objects_count
93
+ @truncated_objects_count ||= objects_count - @limit
94
+ end
95
+
96
+ def objects_count
97
+ @objects_count ||= @objects.size
98
+ end
99
+
100
+ def truncated?
101
+ truncated_objects_count.positive?
102
+ end
103
+ end
@@ -1,161 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ObjectIdentifier
4
- # ObjectIdentifier::Identifier manages construction of the inspect String.
5
- class Identifier
6
- NO_OBJECTS_INDICATOR = "[no objects]"
7
-
8
- # Class method for constructing a self-identifying string for any given
9
- # object or collection of objects.
10
- #
11
- # @overload self.identify(obj, *args)
12
- # @param obj [Object] the object to identify
13
- # @param args [*] (optional) a list of arguments to identify for this
14
- # object or for each object in this collection
15
- # @overload self.identify(obj, *args, options)
16
- # @param obj [Object] the object to identify
17
- # @param args [*] (optional) (default :id) a list of arguments to identify
18
- # for this object
19
- # @param [Hash] options the options for building a customized
20
- # self-identifier
21
- # @option options [String, nil] :klass object class name override
22
- # @option options [Integer] :limit maximum number of objects to display
23
- # from a collection
24
- #
25
- # @return [String] a self-identifying string like `Class[id:1, name:'temp']`
26
- #
27
- # @example
28
- # ObjectIdentifier::Identifier.identify(
29
- # OpenStruct.new(a: 1, b: '2', c: :"3"), :a, :b, :c)
30
- # # => "OpenStruct[a:1, b:\"2\", c::\"3\"]"
31
- #
32
- # ObjectIdentifier::Identifier.identify(1, :to_s)
33
- # # => "Integer[to_s:\"1\"]"
34
- # ObjectIdentifier::Identifier.identify(nil)
35
- # # => "[no objects]"
36
- #
37
- # ObjectIdentifier::Identifier.identify(%w(1 2), :to_i, :to_f)
38
- # # => "String[to_i:1, to_f:1.0], String[to_i:2, to_f:2.0]"
39
- #
40
- # ObjectIdentifier::Identifier.identify((1..10).to_a, :to_f, limit: 2)
41
- # # => "Integer[to_f:1.0], Integer[to_f:2.0], ... (8 more)"
42
- def self.identify(*args, **kargs)
43
- new(*args, **kargs).to_s
44
- end
45
-
46
- def initialize(objects, *args, limit: nil, klass: :not_given)
47
- @objects = ArrayWrap.call(objects)
48
- @attributes = args.empty? ? [:id] : args
49
- @limit = (limit || @objects.size).to_i
50
- @klass = klass
51
- end
52
-
53
- # Output the self-identifying string for an instance of
54
- # ObjectIdentifier::Identifier. Will either return a single object
55
- # representation or a list of object representations, based on the number of
56
- # objects we're identifying.
57
- #
58
- # @return [String] a string representing the object or list of objects
59
- def to_s
60
- if many?
61
- format_multiple_objects
62
- else
63
- format_single_object
64
- end
65
- end
66
-
67
- private
68
-
69
- def format_multiple_objects
70
- objects =
71
- @objects.first(@limit).map { |obj| format(obj) }
72
-
73
- objects << "... (#{truncated_objects_count} more)" if truncated?
74
-
75
- objects.join(", ")
76
- end
77
-
78
- def format_single_object
79
- object = @objects.first if @objects.respond_to?(:first)
80
-
81
- format(object)
82
- end
83
-
84
- def format(object)
85
- return NO_OBJECTS_INDICATOR if blank?(object)
86
-
87
- "#{class_name(object)}[#{format_attributes(evaluate_attributes(object))}]"
88
- end
89
-
90
- def format_attributes(attributes_hash)
91
- return if attributes_hash.empty?
92
-
93
- attributes_hash.
94
- map(&format_attributes_map_block(attributes_hash)).
95
- join(", ")
96
- end
97
-
98
- def format_attributes_map_block(attributes_hash)
99
- if attributes_hash.one?
100
- ->(_key, value) { value.inspect_lit }
101
- else
102
- ->(key, value) { "#{key}:#{value.inspect_lit}" }
103
- end
104
- end
105
-
106
- # @return [Hash]
107
- def evaluate_attributes(object)
108
- @attributes.each_with_object({}) { |key, acc|
109
- if object.respond_to?(key, :include_private)
110
- acc[key] = object.send(key)
111
- elsif key.to_s.start_with?("@")
112
- acc[key] = object.instance_variable_get(key)
113
- end
114
- }
115
- end
116
-
117
- def class_name(object)
118
- klass_given? ? @klass : object.class.name
119
- end
120
-
121
- def truncated_objects_count
122
- objects_count - @limit
123
- end
124
-
125
- def objects_count
126
- @objects_count ||= @objects.size
127
- end
128
-
129
- def klass_given?
130
- @klass != :not_given
131
- end
132
-
133
- def blank?(object)
134
- object.nil? || object == [] || object == {}
135
- end
136
-
137
- def many?
138
- objects_count > 1
139
- end
3
+ # ObjectIdentifier::Identifier manages construction of identification outputs
4
+ # using the passed in formatter_class.
5
+ class ObjectIdentifier::Identifier
6
+ # NOTE: `kargs` may be specific to the Formatter being called.
7
+ def self.call(
8
+ objects,
9
+ *attributes,
10
+ formatter_class: default_formatter_class,
11
+ **formatter_options)
12
+ formatter_class.(objects, *attributes, **formatter_options)
13
+ end
140
14
 
141
- def truncated?
142
- truncated_objects_count.positive?
143
- end
15
+ def self.default_formatter_class
16
+ ObjectIdentifier.configuration.formatter_class
17
+ end
144
18
 
145
- # ObjectIdentifier::Identifier::ArrayWrap mirrors the implementation of
146
- # Rails' {Array.wrap} method. This allows us to get around objects that
147
- # respond to `to_a` (such as Struct) and, instead, utilize either `to_ary`
148
- # or just actually wrapping the object in an Array.
149
- class ArrayWrap
150
- def self.call(object)
151
- if object.nil?
152
- []
153
- elsif object.respond_to?(:to_ary)
154
- object.to_ary || [object]
155
- else
156
- [object]
157
- end
158
- end
159
- end
19
+ def self.default_attributes
20
+ ObjectIdentifier.configuration.default_attributes
160
21
  end
161
22
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ObjectIdentifier
4
- VERSION = "0.4.1"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -3,10 +3,63 @@
3
3
  # ObjectIdentifier is the base namespace for all modules/classes related to the
4
4
  # object_identifier gem.
5
5
  module ObjectIdentifier
6
+ # ObjectIdentifier::ArrayWrap mirrors the implementation of Rails'
7
+ # {Array.wrap} method. This allows us to get around objects that respond to
8
+ # `to_a` (such as Struct) and, instead, either utilize `to_ary` or just
9
+ # actually wrap the object in an Array ourselves.
10
+ class ArrayWrap
11
+ def self.call(object)
12
+ if object.nil?
13
+ []
14
+ elsif object.respond_to?(:to_ary)
15
+ object.to_ary || [object]
16
+ else
17
+ [object]
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.configuration
23
+ @configuration ||= Configuration.new
24
+ end
25
+
26
+ def self.configure
27
+ yield(configuration)
28
+ end
29
+
30
+ def self.reset_configuration
31
+ @configuration = Configuration.new
32
+ end
33
+
34
+ # ObjectIdentifier::Configuration stores the default configuration options for
35
+ # the ObjectIdentifier gem. Modification of attributes is possible at any
36
+ # time, and values will persist for the duration of the running process.
37
+ class Configuration
38
+ attr_reader :formatter_class,
39
+ :default_attributes
40
+
41
+ def initialize
42
+ @formatter_class = ObjectIdentifier::StringFormatter
43
+ @default_attributes = %i[id]
44
+ end
45
+
46
+ def formatter_class=(value)
47
+ unless value.is_a?(Class)
48
+ raise TypeError, "Formatter must be a Class constant"
49
+ end
50
+
51
+ @formatter_class = value
52
+ end
53
+
54
+ def default_attributes=(value)
55
+ @default_attributes = value.to_a.map!(&:to_sym)
56
+ end
57
+ end
6
58
  end
7
59
 
8
60
  require "object_identifier/version"
9
61
  require "object_identifier/identifier"
62
+ require "object_identifier/formatters/string_formatter"
10
63
  require "core_ext/object"
11
64
  require "core_ext/string"
12
65
  require "core_ext/symbol"
@@ -10,6 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = ["Paul DobbinSchmaltz", "Evan Sherwood"]
11
11
  spec.email = ["p.dobbinschmaltz@icloud.com"]
12
12
  spec.required_ruby_version = ">= 2.4.0"
13
+ spec.metadata = { "rubygems_mfa_required" => "true" }
13
14
 
14
15
  spec.summary = "ObjectIdentifier identifies an object by its class name and attributes."
15
16
  spec.description = "Object Identifier allows quick, easy, and uniform identification of an object by inspecting its class name and outputting any desirable attributes/methods. It is great for logging, sending descriptive notification messages, etc."
@@ -32,10 +33,12 @@ Gem::Specification.new do |spec|
32
33
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
34
  spec.require_paths = ["lib"]
34
35
 
36
+ spec.add_development_dependency "benchmark-ips"
35
37
  spec.add_development_dependency "bundler"
36
38
  spec.add_development_dependency "byebug"
37
39
  spec.add_development_dependency "minitest"
38
40
  spec.add_development_dependency "minitest-reporters"
41
+ spec.add_development_dependency "much-stub"
39
42
  spec.add_development_dependency "pry"
40
43
  spec.add_development_dependency "pry-byebug"
41
44
  spec.add_development_dependency "rake"
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Play from the pry console with:
4
+ # play scripts/benchmarking/formatters.rb
5
+
6
+ require "benchmark/ips"
7
+
8
+ custom_formatter_klasses ||= []
9
+
10
+ formatter_klasses = [
11
+ ObjectIdentifier::StringFormatter,
12
+ *Array(custom_formatter_klasses)
13
+ ].freeze
14
+
15
+ MyObject ||= Struct.new(:id, :name)
16
+
17
+ objects = [
18
+ MyObject.new(id: 1, name: "NAME1"),
19
+ MyObject.new(id: 2, name: "NAME2"),
20
+ MyObject.new(id: 3, name: "NAME3")
21
+ ].freeze
22
+
23
+ puts "== Averaged ============================================================="
24
+ Benchmark.ips { |x|
25
+ formatter_klasses.each do |formatter_klass|
26
+ x.report(formatter_klass) {
27
+ formatter_klass.new(objects[0]).call
28
+ formatter_klass.new(objects[0], %i[id name]).call
29
+ formatter_klass.new(objects[0], klass: "CustomClass").call
30
+ formatter_klass.new(objects[0], %i[id name], klass: "CustomClass").call
31
+ formatter_klass.new(objects, limit: 2).call
32
+ formatter_klass.new(objects, %i[id name], klass: "CustomClass", limit: 2).call
33
+ }
34
+ end
35
+
36
+ x.compare!
37
+ }
38
+ puts "== Done"
39
+
40
+ puts "== Individualized ======================================================="
41
+ Benchmark.ips { |x|
42
+ # rubocop:disable Style/CombinableLoops
43
+ formatter_klasses.each do |formatter_klass|
44
+ x.report("#{formatter_klass} - Default Attributes") {
45
+ formatter_klass.new(objects[0]).call
46
+ }
47
+ end
48
+ formatter_klasses.each do |formatter_klass|
49
+ x.report("#{formatter_klass} - Custom Attributes") {
50
+ formatter_klass.new(objects[0], %i[id name]).call
51
+ }
52
+ end
53
+ formatter_klasses.each do |formatter_klass|
54
+ x.report("#{formatter_klass} - Custom Class") {
55
+ formatter_klass.new(objects[0], klass: "CustomClass").call
56
+ }
57
+ end
58
+ formatter_klasses.each do |formatter_klass|
59
+ x.report("#{formatter_klass} - Custom Attributes & Custom Class") {
60
+ formatter_klass.new(objects[0], %i[id name], klass: "CustomClass").call
61
+ }
62
+ end
63
+ formatter_klasses.each do |formatter_klass|
64
+ x.report("#{formatter_klass} - Limit 2") {
65
+ formatter_klass.new(objects, limit: 2).call
66
+ }
67
+ end
68
+ formatter_klasses.each do |formatter_klass|
69
+ x.report("#{formatter_klass} - Custom Attributes & Custom Class & Limit 2") {
70
+ formatter_klass.new(objects, %i[id name], klass: "CustomClass", limit: 2).call
71
+ }
72
+ end
73
+ # rubocop:enable Style/CombinableLoops
74
+
75
+ x.compare!
76
+ }
77
+ puts "== Done"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: object_identifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul DobbinSchmaltz
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-12-30 00:00:00.000000000 Z
12
+ date: 2023-01-05 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: benchmark-ips
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: bundler
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -67,6 +81,20 @@ dependencies:
67
81
  - - ">="
68
82
  - !ruby/object:Gem::Version
69
83
  version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: much-stub
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
70
98
  - !ruby/object:Gem::Dependency
71
99
  name: pry
72
100
  requirement: !ruby/object:Gem::Requirement
@@ -160,6 +188,7 @@ executables: []
160
188
  extensions: []
161
189
  extra_rdoc_files: []
162
190
  files:
191
+ - ".github/workflows/ci.yml"
163
192
  - ".gitignore"
164
193
  - ".rubocop"
165
194
  - ".rubocop.yml"
@@ -176,13 +205,16 @@ files:
176
205
  - lib/core_ext/string.rb
177
206
  - lib/core_ext/symbol.rb
178
207
  - lib/object_identifier.rb
208
+ - lib/object_identifier/formatters/string_formatter.rb
179
209
  - lib/object_identifier/identifier.rb
180
210
  - lib/object_identifier/version.rb
181
211
  - object_identifier.gemspec
212
+ - scripts/benchmarking/formatters.rb
182
213
  homepage: https://github.com/pdobb/object_identifier
183
214
  licenses:
184
215
  - MIT
185
- metadata: {}
216
+ metadata:
217
+ rubygems_mfa_required: 'true'
186
218
  post_install_message:
187
219
  rdoc_options: []
188
220
  require_paths: