pluggability 0.9.0 → 0.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 843f2f58748eaeb19465a3e12811c495c218b84bfd0561dd7266b1aa039c2088
4
- data.tar.gz: 376ce248e38a0547faaff01bfc033baf099e3cc33431387f56c2f5f789e896cf
3
+ metadata.gz: acdddb8e543aa6046ffbdbd68d67588eed0cb3ba2ab70bf2f2c1ea8fb5e55e86
4
+ data.tar.gz: 06e1b5426c52c27250e940a401327a6176ce666d22b7cba988746c85de96cb95
5
5
  SHA512:
6
- metadata.gz: 26b4d2466c36294eb1d336c88ff1a61b6c73283626d21766d3929b9ce86babc8144889c7f27adf2fd6b44b5177c2988b4c7f4b60ce9b66e9ad8825d2dc40f6c6
7
- data.tar.gz: d99e802e78109839a9e8df5ff75d9493323a4fb72328f62c63d841cdf5199d73ba3aac0bd46f161db1c83cb7f70ef4c74c28485b7ecb9ff97c9bc2d83d9ba96d
6
+ metadata.gz: f84aae2fa72d6425a69592bb4ea1fcc37e6e5dc96d9b03ab1f6c5d2954f86806f4316dd4e9baf0cb7111ffb1f9b2d682c43b44305750f84a66afb8faaf738368
7
+ data.tar.gz: 01bc40509082e86090d3770491e15473b0fdf5cabbb3021ec8bfdf4a9e56b73f579e43cfcebf5909454da4ec1802bae201ad68ea2107281ae7a15bc24e9bfaed
checksums.yaml.gz.sig CHANGED
Binary file
data/History.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ---
4
4
 
5
+ ## v0.10.0 [2025-07-12] Michael Granger <ged@faeriemud.org>
6
+
7
+ Improvements:
8
+
9
+ - Remove support for non-Ruby idiomatic plugin paths
10
+ - Add support for newer Ruby features, e.g., Module#set_temporary_name.
11
+
12
+
5
13
  ## v0.9.0 [2023-06-08] Michael Granger <ged@faeriemud.org>
6
14
 
7
15
  Improvements:
data/lib/pluggability.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
3
2
 
4
3
  require 'loggability' unless defined?( Loggability )
5
4
 
5
+
6
6
  # The Pluggability module
7
7
  module Pluggability
8
8
  extend Loggability
@@ -12,7 +12,7 @@ module Pluggability
12
12
 
13
13
 
14
14
  # Library version
15
- VERSION = '0.9.0'
15
+ VERSION = '0.10.0'
16
16
 
17
17
 
18
18
  # An exception class for Pluggability specific errors.
@@ -20,12 +20,26 @@ module Pluggability
20
20
  FactoryError = PluginError
21
21
 
22
22
 
23
+ module StringRefinements
24
+ refine( String ) do
25
+
26
+ def uncamelcase
27
+ return self.gsub( /([a-z0-9])([A-Z])/, "\\1_\\2" )
28
+ end
29
+
30
+ end
31
+ end
32
+ using StringRefinements
33
+
34
+
23
35
  ### Add the @derivatives instance variable to including classes.
24
36
  def self::extend_object( obj )
25
37
  obj.instance_variable_set( :@plugin_prefixes, [] )
26
38
  obj.instance_variable_set( :@plugin_exclusions, [] )
27
39
  obj.instance_variable_set( :@derivatives, {} )
28
40
 
41
+ obj.singleton_class.attr_accessor( :plugin_name )
42
+
29
43
  Pluggability.pluggable_classes << obj
30
44
 
31
45
  super
@@ -125,15 +139,30 @@ module Pluggability
125
139
  return base.name
126
140
  end
127
141
  end
128
- alias factory_type plugin_type
142
+ alias_method :factory_type, :plugin_type
129
143
 
130
144
 
131
145
  ### Inheritance callback -- Register subclasses in the derivatives hash
132
146
  ### so that ::create knows about them.
133
147
  def inherited( subclass )
134
- plugin_class = Pluggability.plugin_base_class( subclass )
148
+ Pluggability.log.debug " %p inherited by %p" % [ self, subclass ]
149
+ self.register_plugin_type( subclass )
150
+ super
151
+ end
135
152
 
136
- Pluggability.logger.debug "%p inherited by %p" % [ plugin_class, subclass ]
153
+
154
+ ### Override Module#set_temporary_name so +new_name+ can be used to derive the
155
+ ### plugin name. Note that this does *not* detect if you later assign the
156
+ ### anonymous class to a constant and thus clear its temporary name.
157
+ def set_temporary_name( new_name )
158
+ super
159
+ self.register_plugin_type( self )
160
+ end
161
+
162
+
163
+ ### Register the given +subclass+ as a plugin type of the receiving Pluggable class.
164
+ def register_plugin_type( subclass )
165
+ plugin_class = Pluggability.plugin_base_class( subclass )
137
166
  keys = [ subclass ]
138
167
 
139
168
  # If it's not an anonymous class, make some keys out of variants of its name
@@ -153,13 +182,8 @@ module Pluggability
153
182
  plugin_class.derivatives[ key ] = subclass
154
183
  end
155
184
 
156
- # Add a name attribute to it
157
- class << subclass
158
- attr_reader :plugin_name
159
- end
160
- subclass.instance_variable_set( :@plugin_name, keys.last )
161
-
162
- super
185
+ Pluggability.log.debug "Setting plugin name of %p to %p" % [ subclass, keys.last ]
186
+ subclass.plugin_name = keys.last
163
187
  end
164
188
 
165
189
 
@@ -168,19 +192,16 @@ module Pluggability
168
192
  def make_derivative_names( subclass )
169
193
  keys = []
170
194
 
171
- simple_name = subclass.name.sub( /^.*::/i, '' ).sub( /\W+$/, '' )
195
+ # Order is important here, as the last non-nil one becomes the plugin_name.
196
+ simple_name = subclass.name.sub( /\A.*::/, '' ).sub( /\A(\w+).*/, '\\1' )
172
197
  keys << simple_name << simple_name.downcase
173
- keys << simple_name.gsub( /([a-z0-9])([A-Z])/, "\\1_\\2" ).downcase
198
+ keys << simple_name.uncamelcase.downcase
174
199
 
175
- # Handle class names like 'FooBar' for 'Bar' factories.
176
- Pluggability.log.debug "Inherited %p for %p-type plugins" % [ subclass, self.plugin_type ]
177
- if subclass.name.match( /(?:.*::)?(\w+)(?:#{self.plugin_type})/i )
178
- keys << Regexp.last_match[1].downcase
179
- else
180
- keys << subclass.name.sub( /.*::/, '' ).downcase
181
- end
200
+ simpler_name = simple_name.sub( /(?:#{self.plugin_type})\z/, '' )
201
+ keys << simpler_name << simpler_name.downcase
202
+ keys << simpler_name.uncamelcase.downcase
182
203
 
183
- return keys
204
+ return keys.uniq
184
205
  end
185
206
 
186
207
 
@@ -361,6 +382,7 @@ module Pluggability
361
382
 
362
383
  candidate_paths = candidates.
363
384
  flat_map {|path| Gem.find_latest_files( path ) }.
385
+ uniq.
364
386
  reject {|path| self.is_excluded_path?( path ) || ! File.file?(path) }
365
387
  Pluggability.log.debug "Valid candidates in the current gemset: %p" % [ candidate_paths ]
366
388
 
@@ -374,7 +396,7 @@ module Pluggability
374
396
  prefixes = self.plugin_prefixes
375
397
  prefixes << '' if prefixes.empty?
376
398
 
377
- return prefixes.flat_map {|pre| self.make_require_path(mod_name, pre) }
399
+ return prefixes.flat_map {|pre| self.make_require_path(mod_name, pre) }.uniq
378
400
  end
379
401
 
380
402
 
@@ -385,17 +407,12 @@ module Pluggability
385
407
  ### "drivers/SocketDataDriver", "drivers/socket", "drivers/Socket"]
386
408
  def make_require_path( modname, subdir )
387
409
  path = []
388
- myname = self.plugin_type
410
+ myname = self.plugin_type.uncamelcase.downcase
411
+ modname = modname.uncamelcase.downcase
389
412
 
390
413
  # Make permutations of the two parts
391
414
  path << modname
392
- path << modname.downcase
393
- path << modname + myname
394
- path << modname.downcase + myname
395
- path << modname.downcase + myname.downcase
396
- path << modname + '_' + myname
397
- path << modname.downcase + '_' + myname
398
- path << modname.downcase + '_' + myname.downcase
415
+ path << modname + '_' + myname
399
416
 
400
417
  # If a non-empty subdir was given, prepend it to all the items in the
401
418
  # path
data/spec/helpers.rb CHANGED
@@ -1,19 +1,28 @@
1
- #!/usr/bin/ruby
2
- # coding: utf-8
1
+ # -*- ruby -*-
3
2
 
4
3
  require 'rspec'
4
+ require 'diff/lcs'
5
5
  require 'loggability/spechelpers'
6
6
  require 'pluggability'
7
7
 
8
- ### Mock with Rspec
8
+ # Mock with Rspec
9
9
  RSpec.configure do |config|
10
+ config.mock_with( :rspec ) do |mock|
11
+ mock.syntax = :expect
12
+ end
10
13
 
11
- config.run_all_when_everything_filtered = true
14
+ config.disable_monkey_patching!
15
+ config.example_status_persistence_file_path = "spec/.status"
12
16
  config.filter_run :focus
13
- config.order = 'random'
14
- config.warnings = true
15
- config.mock_with( :rspec ) do |mock_config|
16
- mock_config.syntax = :expect
17
+ config.filter_run_when_matching :focus
18
+ config.order = :random
19
+ config.profile_examples = 5
20
+ config.run_all_when_everything_filtered = true
21
+ config.shared_context_metadata_behavior = :apply_to_host_groups
22
+ config.warnings = true
23
+
24
+ config.expect_with( :rspec ) do |expectations|
25
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
17
26
  end
18
27
 
19
28
  config.include( Loggability::SpecHelpers )
@@ -3,7 +3,7 @@
3
3
  require_relative 'helpers'
4
4
 
5
5
  require 'pluggability'
6
-
6
+ require 'loggability'
7
7
 
8
8
  #
9
9
  # Testing classes
@@ -34,7 +34,7 @@ class SubSubPlugin < SubPlugin; end
34
34
  #
35
35
  # Examples
36
36
  #
37
- describe Pluggability do
37
+ RSpec.describe Pluggability do
38
38
 
39
39
  before( :each ) do
40
40
  Plugin.plugin_exclusions = []
@@ -101,9 +101,9 @@ describe Pluggability do
101
101
  at_least( :once ).
102
102
  and_return( ['/some/path/to/plugins/dazzle.rb'] )
103
103
  expect( Kernel ).to receive( :require ).with( '/some/path/to/plugins/dazzle.rb' ) do |*args|
104
- loaded_class = Class.new( Plugin )
105
- # Simulate a named class, since we're not really requiring
106
- Plugin.derivatives['dazzle'] = loaded_class
104
+ loaded_class = Class.new( Plugin ) do
105
+ set_temporary_name 'Plugin::Dazzle (testing class)'
106
+ end
107
107
  true
108
108
  end
109
109
 
@@ -111,11 +111,31 @@ describe Pluggability do
111
111
  end
112
112
 
113
113
 
114
+ it "will load new plugins from the require path if given a camel-cased class name" do
115
+ loaded_class = nil
116
+
117
+ expect( Gem ).to receive( :find_latest_files ).
118
+ at_least( :once ).
119
+ and_return( ['/some/path/to/plugins/razzle_dazzle.rb'] )
120
+ expect( Kernel ).to receive( :require ) do |require_path|
121
+ expect( require_path ).to eq( '/some/path/to/plugins/razzle_dazzle.rb' )
122
+
123
+ loaded_class = Class.new( Plugin ) do
124
+ set_temporary_name 'Plugin::RazzleDazzle (testing class)'
125
+ end
126
+
127
+ true
128
+ end
129
+
130
+ expect( Plugin.create(:RazzleDazzle) ).to be_an_instance_of( loaded_class )
131
+ end
132
+
133
+
114
134
  it "will output a sensible description of what it tried to load if requiring a " +
115
135
  "derivative fails" do
116
136
 
117
137
  # at least 6 -> 3 variants * 2 paths
118
- expect( Gem ).to receive( :find_latest_files ).at_least( 6 ).times.
138
+ expect( Gem ).to receive( :find_latest_files ).at_least( 4 ).times.
119
139
  and_return( [] )
120
140
 
121
141
  expect {
@@ -293,7 +313,7 @@ describe Pluggability do
293
313
 
294
314
 
295
315
  it "still knows what the simplest version of its plugin name is" do
296
- expect( SubSubPlugin.plugin_name ).to eq( 'subsub' )
316
+ expect( SubSubPlugin.plugin_name ).to eq( 'sub_sub' )
297
317
  end
298
318
 
299
319
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,40 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pluggability
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
8
8
  - Martin Chase
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain:
12
11
  - |
13
12
  -----BEGIN CERTIFICATE-----
14
- MIID+DCCAmCgAwIBAgIBBTANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdnZWQv
15
- REM9RmFlcmllTVVEL0RDPW9yZzAeFw0yMzAxMTYxNzE2MDlaFw0yNDAxMTYxNzE2
16
- MDlaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
17
- hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvyVhkRzvlEs0fe7145BYLfN6njX9ih5H
18
- L60U0p0euIurpv84op9CNKF9tx+1WKwyQvQP7qFGuZxkSUuWcP/sFhDXL1lWUuIl
19
- M4uHbGCRmOshDrF4dgnBeOvkHr1fIhPlJm5FO+Vew8tSQmlDsosxLUx+VB7DrVFO
20
- 5PU2AEbf04GGSrmqADGWXeaslaoRdb1fu/0M5qfPTRn5V39sWD9umuDAF9qqil/x
21
- Sl6phTvgBrG8GExHbNZpLARd3xrBYLEFsX7RvBn2UPfgsrtvpdXjsHGfpT3IPN+B
22
- vQ66lts4alKC69TE5cuKasWBm+16A4aEe3XdZBRNmtOu/g81gvwA7fkJHKllJuaI
23
- dXzdHqq+zbGZVSQ7pRYHYomD0IiDe1DbIouFnPWmagaBnGHwXkDT2bKKP+s2v21m
24
- ozilJg4aar2okb/RA6VS87o+d7g6LpDDMMQjH4G9OPnJENLdhu8KnPw/ivSVvQw7
25
- N2I4L/ZOIe2DIVuYH7aLHfjZDQv/mNgpAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYD
26
- VR0PBAQDAgSwMB0GA1UdDgQWBBRyjf55EbrHagiRLqt5YAd3yb8k4DANBgkqhkiG
27
- 9w0BAQsFAAOCAYEARYCeUVBWARNKqF0cvNnLJvFf4hdW2+Rtc7NfC5jQvX9a1oom
28
- sfVvS96eER/9cbrphu+vc59EELw4zT+RY3/IesnoE7CaX6zIOFmSmG7K61OHsSLR
29
- KqMygcWwyuPXT2JG7JsGHuxbzgaRWe29HbSjBbLYxiMH8Zxh4tKutxzKF7jb0Ggq
30
- KAf9MH5LwG8IHVIfV5drT14PvgR3tcvmrn1timPyJl+eZ3LNnm9ofOCweuZCq1cy
31
- 4Q8LV3vP2Cofy9q+az3DHdaUGlmMiZZZqKixDr1KSS9nvh0ZrKMOUL1sWj/IaxrQ
32
- RV3y6td14q49t+xnbj00hPlbW7uE2nLJLt2NAoXiE1Nonndz1seB2c6HL79W9fps
33
- E/O12pQjCp/aPUZMt8/8tKW31RIy/KP8XO6OTJNWA8A/oNEI0g5p/LmmEtJKWYr1
34
- WmEdESlpWhzFECctefIF2lsN9vaOuof57RM77t2otrtcscDtNarIqjZsIyqtDvtL
35
- DttITiit0Vwz7bY0
13
+ MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MQwwCgYDVQQDDANnZWQx
14
+ GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
15
+ HhcNMjUwMTAxMDMzMTA5WhcNMjYwMTAxMDMzMTA5WjA+MQwwCgYDVQQDDANnZWQx
16
+ GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
17
+ ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC/JWGRHO+USzR97vXjkFgt
18
+ 83qeNf2KHkcvrRTSnR64i6um/ziin0I0oX23H7VYrDJC9A/uoUa5nGRJS5Zw/+wW
19
+ ENcvWVZS4iUzi4dsYJGY6yEOsXh2CcF46+QevV8iE+UmbkU75V7Dy1JCaUOyizEt
20
+ TH5UHsOtUU7k9TYARt/TgYZKuaoAMZZd5qyVqhF1vV+7/Qzmp89NGflXf2xYP26a
21
+ 4MAX2qqKX/FKXqmFO+AGsbwYTEds1mksBF3fGsFgsQWxftG8GfZQ9+Cyu2+l1eOw
22
+ cZ+lPcg834G9DrqW2zhqUoLr1MTly4pqxYGb7XoDhoR7dd1kFE2a067+DzWC/ADt
23
+ +QkcqWUm5oh1fN0eqr7NsZlVJDulFgdiiYPQiIN7UNsii4Wc9aZqBoGcYfBeQNPZ
24
+ soo/6za/bWajOKUmDhpqvaiRv9EDpVLzuj53uDoukMMwxCMfgb04+ckQ0t2G7wqc
25
+ /D+K9JW9DDs3Yjgv9k4h7YMhW5gftosd+NkNC/+Y2CkCAwEAAaN1MHMwCQYDVR0T
26
+ BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFHKN/nkRusdqCJEuq3lgB3fJvyTg
27
+ MBwGA1UdEQQVMBOBEWdlZEBGYWVyaWVNVUQub3JnMBwGA1UdEgQVMBOBEWdlZEBG
28
+ YWVyaWVNVUQub3JnMA0GCSqGSIb3DQEBCwUAA4IBgQBjrBzCKWzXFigswYSPzGO8
29
+ 9atBtY/eQdcN6KCL+PTzQBD9yePGF7H/xsww3awRauP+D1VUjCFbiiC3Qb0Ww0Qd
30
+ OVA0s10T9KpZ8nb2XyKocSK7TfgDhcyr0V4H2MPxwK9SWYjGGh8z9z9HmT0i3PyX
31
+ fXOSzzEoG6u26HIOg0nxSpitEjiAHBekQxy9ka5NuQbxoxMg+eIHU4rU9IUhu0Rf
32
+ wl4wuvPVE3UQK0v0uqT6rJukEKQ1iNgK5R8klgEIv79XhQPgTkMt31FGfrwOp6HB
33
+ OE0HMwOwY9B0w3aOxxdMQyyRxaZVv3eWE5RimQI7T0TUaxPngtS33ByMZjTeidxi
34
+ ESIUEPVXoBCkFgLW1EVlBb+rG7WLYod4eVll4tKA42Bi2Ju90tqiJ1YQiyuRfCnp
35
+ 8qAqdfV+4u6Huu1KzAuDQCheyEyISsLST37sU/irV3czV6BiFipWag1XiJciRT3A
36
+ wZqCfTNVHTdtsCbfdA1DsA3RdG2iEH3TOHzv1Rqzqh4=
36
37
  -----END CERTIFICATE-----
37
- date: 2023-06-08 00:00:00.000000000 Z
38
+ date: 2025-07-12 00:00:00.000000000 Z
38
39
  dependencies:
39
40
  - !ruby/object:Gem::Dependency
40
41
  name: loggability
@@ -100,7 +101,6 @@ metadata:
100
101
  changelog_uri: https://deveiate.org/code/pluggability/History_md.html
101
102
  source_uri: https://hg.sr.ht/~ged/Pluggability/browse
102
103
  bug_tracker_uri: https://todo.sr.ht/~ged/Pluggability/browse
103
- post_install_message:
104
104
  rdoc_options: []
105
105
  require_paths:
106
106
  - lib
@@ -115,8 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
117
  requirements: []
118
- rubygems_version: 3.3.26
119
- signing_key:
118
+ rubygems_version: 3.6.9
120
119
  specification_version: 4
121
120
  summary: Pluggability is a toolkit for creating plugins.
122
121
  test_files: []
metadata.gz.sig CHANGED
Binary file