mixins 0.1.0.pre.20250527171116
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
- checksums.yaml.gz.sig +0 -0
- data/History.md +7 -0
- data/LICENSE.txt +23 -0
- data/README.md +89 -0
- data/lib/mixins/data_utilities.rb +88 -0
- data/lib/mixins/datadir.rb +59 -0
- data/lib/mixins/delegation.rb +95 -0
- data/lib/mixins/hooks.rb +84 -0
- data/lib/mixins/inspection.rb +28 -0
- data/lib/mixins/method_utilities.rb +92 -0
- data/lib/mixins.rb +20 -0
- data/spec/mixins/data_utilities_spec.rb +266 -0
- data/spec/mixins/datadir_spec.rb +86 -0
- data/spec/mixins/delegation_spec.rb +186 -0
- data/spec/mixins/hooks_spec.rb +86 -0
- data/spec/mixins/inspection_spec.rb +41 -0
- data/spec/mixins/method_utilities_spec.rb +98 -0
- data/spec/mixins_spec.rb +32 -0
- data/spec/spec_helper.rb +25 -0
- data.tar.gz.sig +0 -0
- metadata +106 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 931a539b8bc837e347f9e8daaaa3bbf457f48e4c320512be024bc591852f6ddd
|
4
|
+
data.tar.gz: 94ae6c7269ce07c2578499e51da76641b2b4df11caa5f76bc4dbd691ae61d43e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 25a3c87aa1e640ecc6f9b05c48717434d184a0987b35b78e38c19c5c57b399e2f63be87be3239e56f01800bd17dadefe79dfaabf0cad9b3e4274513f473fe2fa
|
7
|
+
data.tar.gz: 56b6973f4de6917808a36e134575fe30c125f3ac6a9e03f3b507f4b2cae7c8b42ae40d032500d8c8e7f01d106c94811945e2dbd775ca70a2951eba9e141ae239
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data/History.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2025, Michael Granger
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
15
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
16
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
18
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
19
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
20
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
21
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
22
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
23
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# mixins
|
2
|
+
|
3
|
+
home
|
4
|
+
: https://hg.sr.ht/~ged/Mixins
|
5
|
+
|
6
|
+
code
|
7
|
+
: https://hg.sr.ht/~ged/Mixins
|
8
|
+
|
9
|
+
github
|
10
|
+
: https://github.com/ged/mixins
|
11
|
+
|
12
|
+
docs
|
13
|
+
: https://deveiate.org/code/mixins
|
14
|
+
|
15
|
+
|
16
|
+
## Description
|
17
|
+
|
18
|
+
This is a collection of zero-dependency mixins. They're intended to be generically useful for building other software, well-tested, and not add any non-stdlib dependencies.
|
19
|
+
|
20
|
+
The current mixins are:
|
21
|
+
|
22
|
+
- Mixins::DataUtilities
|
23
|
+
- Mixins::Datadir
|
24
|
+
- Mixins::Delegation
|
25
|
+
- Mixins::Hooks
|
26
|
+
- Mixins::Inspection
|
27
|
+
- Mixins::MethodUtilities
|
28
|
+
|
29
|
+
|
30
|
+
## Prerequisites
|
31
|
+
|
32
|
+
* Ruby 3+
|
33
|
+
|
34
|
+
|
35
|
+
## Installation
|
36
|
+
|
37
|
+
$ gem install mixins
|
38
|
+
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
You can check out the current development source with Mercurial via its
|
43
|
+
[project page](https://hg.sr.ht/~ged/Mixins). Or if you prefer Git, via
|
44
|
+
[its Github mirror](https://github.com/ged/mixins).
|
45
|
+
|
46
|
+
After checking out the source, run:
|
47
|
+
|
48
|
+
$ gem install -Ng
|
49
|
+
$ rake setup
|
50
|
+
|
51
|
+
This will install dependencies, and do any other necessary setup for development.
|
52
|
+
|
53
|
+
|
54
|
+
## Authors
|
55
|
+
|
56
|
+
- Michael Granger <ged@faeriemud.org>
|
57
|
+
|
58
|
+
|
59
|
+
## License
|
60
|
+
|
61
|
+
Copyright (c) 2025, Michael Granger
|
62
|
+
All rights reserved.
|
63
|
+
|
64
|
+
Redistribution and use in source and binary forms, with or without
|
65
|
+
modification, are permitted provided that the following conditions are met:
|
66
|
+
|
67
|
+
* Redistributions of source code must retain the above copyright notice,
|
68
|
+
this list of conditions and the following disclaimer.
|
69
|
+
|
70
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
71
|
+
this list of conditions and the following disclaimer in the documentation
|
72
|
+
and/or other materials provided with the distribution.
|
73
|
+
|
74
|
+
* Neither the name of the author/s, nor the names of the project's
|
75
|
+
contributors may be used to endorse or promote products derived from this
|
76
|
+
software without specific prior written permission.
|
77
|
+
|
78
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
79
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
80
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
81
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
82
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
83
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
84
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
85
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
86
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
87
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
88
|
+
|
89
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
require 'mixins' unless defined?( Mixins )
|
6
|
+
|
7
|
+
|
8
|
+
# A collection of miscellaneous functions that are useful for manipulating
|
9
|
+
# complex data structures.
|
10
|
+
#
|
11
|
+
# include Ravn::DataUtilities
|
12
|
+
# newhash = deep_copy( oldhash )
|
13
|
+
#
|
14
|
+
module Mixins::DataUtilities
|
15
|
+
|
16
|
+
###############
|
17
|
+
module_function
|
18
|
+
###############
|
19
|
+
|
20
|
+
|
21
|
+
### Recursively copy the specified +obj+ and return the result.
|
22
|
+
def deep_copy( obj )
|
23
|
+
|
24
|
+
# Handle mocks during testing
|
25
|
+
return obj if obj.class.name == 'RSpec::Mocks::Mock'
|
26
|
+
|
27
|
+
# rubocop:disable Layout/IndentationWidth, Layout/IndentationStyle
|
28
|
+
return case obj
|
29
|
+
when NilClass, Numeric, TrueClass, FalseClass, Symbol,
|
30
|
+
Module, Encoding, IO, Tempfile
|
31
|
+
obj
|
32
|
+
|
33
|
+
when Array
|
34
|
+
obj.map {|o| deep_copy(o) }
|
35
|
+
|
36
|
+
when Hash
|
37
|
+
newhash = {}
|
38
|
+
newhash.default_proc = obj.default_proc if obj.default_proc
|
39
|
+
obj.each do |k,v|
|
40
|
+
newhash[ deep_copy(k) ] = deep_copy( v )
|
41
|
+
end
|
42
|
+
newhash
|
43
|
+
|
44
|
+
else
|
45
|
+
obj.clone
|
46
|
+
end
|
47
|
+
# rubocop:enable Layout/IndentationWidth, Layout/IndentationStyle
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
### Return a duplicate of the given +object+ with its Symbol keys transformed
|
52
|
+
### into Strings.
|
53
|
+
def stringify_keys( object )
|
54
|
+
case object
|
55
|
+
when Hash
|
56
|
+
return object.each_with_object( {} ) do |(key,val), newhash|
|
57
|
+
key = key.to_s if key.is_a?( Symbol )
|
58
|
+
newhash[ key ] = stringify_keys( val )
|
59
|
+
end
|
60
|
+
when Array
|
61
|
+
return object.map {|el| stringify_keys(el) }
|
62
|
+
else
|
63
|
+
return object
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
### Return a duplicate of the given +object+ with its identifier-like String keys
|
69
|
+
### transformed into Symbols.
|
70
|
+
def symbolify_keys( object )
|
71
|
+
case object
|
72
|
+
when Hash
|
73
|
+
return object.each_with_object( {} ) do |(key,val), newhash|
|
74
|
+
key = key.to_sym if key.respond_to?( :to_sym ) &&
|
75
|
+
key.match?( /\A\w+\Z/ )
|
76
|
+
newhash[ key ] = symbolify_keys( val )
|
77
|
+
end
|
78
|
+
when Array
|
79
|
+
return object.map {|el| symbolify_keys(el) }
|
80
|
+
else
|
81
|
+
return object
|
82
|
+
end
|
83
|
+
end
|
84
|
+
alias_method :internify_keys, :symbolify_keys
|
85
|
+
|
86
|
+
end # module Mixins::DataUtilities
|
87
|
+
|
88
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'rubygems'
|
5
|
+
|
6
|
+
require 'mixins' unless defined?( Mixins )
|
7
|
+
|
8
|
+
|
9
|
+
# When extended in a class, automatically set the path to a DATA_DIR
|
10
|
+
# constant, derived from the class name. Prefers environmental
|
11
|
+
# override, Gem path, then local filesystem pathing.
|
12
|
+
#
|
13
|
+
# This can also be called manually if the including class name doesn't
|
14
|
+
# match the gem, or something else esoteric.
|
15
|
+
#
|
16
|
+
# DATA_DIR is a Pathname object.
|
17
|
+
#
|
18
|
+
module Mixins::Datadir
|
19
|
+
|
20
|
+
### Extend hook: Set the DATA_DIR constant in the extending
|
21
|
+
### class.
|
22
|
+
###
|
23
|
+
def self::extended( obj )
|
24
|
+
name = obj.name.downcase.gsub( '::', '-' )
|
25
|
+
dir = self.find_datadir( name )
|
26
|
+
|
27
|
+
obj.const_set( :DATA_DIR, dir )
|
28
|
+
obj.singleton_class.attr_accessor :data_dir
|
29
|
+
obj.data_dir = dir
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
### Return a pathname object for the extended class DATA_DIR. This
|
34
|
+
### allows for the DATA_DIR constant to be used transparently between
|
35
|
+
### development (local checkout) and production (gem installation)
|
36
|
+
### environments.
|
37
|
+
###
|
38
|
+
def self::find_datadir( gemname, env: nil )
|
39
|
+
unless env
|
40
|
+
comps = gemname.split( '-' )
|
41
|
+
env = comps.size > 1 ? comps.last : comps.first
|
42
|
+
env = "%s_DATADIR" % [ env.upcase ]
|
43
|
+
end
|
44
|
+
|
45
|
+
loaded_gemspec = Gem.loaded_specs[ gemname ]
|
46
|
+
|
47
|
+
dir = if ENV[ env ]
|
48
|
+
Pathname( ENV[ env ] )
|
49
|
+
elsif loaded_gemspec && File.exist?( loaded_gemspec.datadir )
|
50
|
+
Pathname( loaded_gemspec.datadir )
|
51
|
+
else
|
52
|
+
caller_path = caller_locations( 2, 1 ).first.absolute_path
|
53
|
+
Pathname( caller_path ).dirname.parent.parent + "data/#{gemname}"
|
54
|
+
end
|
55
|
+
|
56
|
+
return dir
|
57
|
+
end
|
58
|
+
|
59
|
+
end # module Mixins::Datadir
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'mixins' unless defined?( Mixins )
|
4
|
+
|
5
|
+
|
6
|
+
# A collection of various delegation code-generators that can be used to define
|
7
|
+
# delegation through other methods, to instance variables, etc.
|
8
|
+
module Mixins::Delegation
|
9
|
+
|
10
|
+
### Define the given +delegated_methods+ as delegators to the like-named method
|
11
|
+
### of the return value of the +delegate_method+.
|
12
|
+
###
|
13
|
+
### class MyClass
|
14
|
+
### extend Strelka::Delegation
|
15
|
+
###
|
16
|
+
### # Delegate the #bound?, #err, and #result2error methods to the connection
|
17
|
+
### # object returned by the #connection method. This allows the connection
|
18
|
+
### # to still be loaded on demand/overridden/etc.
|
19
|
+
### def_method_delegators :connection, :bound?, :err, :result2error
|
20
|
+
###
|
21
|
+
### def connection
|
22
|
+
### @connection ||= self.connect
|
23
|
+
### end
|
24
|
+
### end
|
25
|
+
###
|
26
|
+
def def_method_delegators( delegate_method, *delegated_methods )
|
27
|
+
delegated_methods.each do |name|
|
28
|
+
body = Mixins::Delegation.make_method_delegator( delegate_method, name )
|
29
|
+
define_method( name, &body )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
### Define the given +delegated_methods+ as delegators to the like-named method
|
35
|
+
### of the specified +ivar+. This is pretty much identical with how 'Forwardable'
|
36
|
+
### from the stdlib does delegation, but it's reimplemented here for consistency.
|
37
|
+
###
|
38
|
+
### class MyClass
|
39
|
+
### extend Strelka::Delegation
|
40
|
+
###
|
41
|
+
### # Delegate the #each method to the @collection ivar
|
42
|
+
### def_ivar_delegators :@collection, :each
|
43
|
+
###
|
44
|
+
### end
|
45
|
+
###
|
46
|
+
def def_ivar_delegators( ivar, *delegated_methods )
|
47
|
+
delegated_methods.each do |name|
|
48
|
+
body = Mixins::Delegation.make_ivar_delegator( ivar, name )
|
49
|
+
define_method( name, &body )
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
### Define the given +delegated_methods+ as delegators to the like-named class
|
55
|
+
### method.
|
56
|
+
def def_class_delegators( *delegated_methods )
|
57
|
+
delegated_methods.each do |name|
|
58
|
+
define_method( name ) do |*args|
|
59
|
+
self.class.__send__( name, *args )
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
###############
|
66
|
+
module_function
|
67
|
+
###############
|
68
|
+
|
69
|
+
### Make the body of a delegator method that will delegate to the +name+ method
|
70
|
+
### of the object returned by the +delegate+ method.
|
71
|
+
def make_method_delegator( delegate, name )
|
72
|
+
return ->( *args, **kwargs, &block ) do
|
73
|
+
self.__send__( delegate ).__send__( name, *args, **kwargs, &block )
|
74
|
+
rescue => err
|
75
|
+
bt = err.backtrace_locations
|
76
|
+
bt.shift
|
77
|
+
raise( err, err.message, bt, cause: err )
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
### Make the body of a delegator method that will delegate calls to the +name+
|
83
|
+
### method to the given +ivar+.
|
84
|
+
def make_ivar_delegator( ivar_name, name )
|
85
|
+
return ->( *args, **kwargs, &block ) do
|
86
|
+
ivar = self.instance_variable_get( ivar_name )
|
87
|
+
ivar.__send__( name, *args, **kwargs, &block )
|
88
|
+
rescue => err
|
89
|
+
bt = err.backtrace_locations
|
90
|
+
bt.shift
|
91
|
+
raise( err, err.message, bt, cause: err )
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end # module Delegation
|
data/lib/mixins/hooks.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'mixins' unless defined?( Mixins )
|
4
|
+
|
5
|
+
|
6
|
+
# Methods for declaring hook methods.
|
7
|
+
#
|
8
|
+
# class MyClass
|
9
|
+
# extend Mixins::Hooks
|
10
|
+
#
|
11
|
+
# define_hook :before_fork
|
12
|
+
# define_hook :after_fork
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# MyClass.before_fork do
|
16
|
+
# @socket.close
|
17
|
+
# end
|
18
|
+
# MyClass.after_fork do
|
19
|
+
# @socket = Socket.new
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# MyClass.run_before_fork_hook
|
23
|
+
# fork do
|
24
|
+
# MyClass.run_after_fork_hook
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
#
|
28
|
+
module Mixins::Hooks
|
29
|
+
|
30
|
+
### Extension callback -- also extend it with MethodUtilities
|
31
|
+
def self::extended( obj )
|
32
|
+
super
|
33
|
+
obj.extend( Mixins::MethodUtilities )
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
### Create the body of a method that can register a callback for the specified +hook+.
|
38
|
+
def self::make_registration_method( callbackset, **options )
|
39
|
+
return lambda do |&callback|
|
40
|
+
raise LocalJumpError, "no callback given" unless callback
|
41
|
+
set = self.public_send( callbackset ) or raise "No hook registration set!"
|
42
|
+
set.add( callback )
|
43
|
+
|
44
|
+
callback.call if self.public_send( "#{callbackset}_run?" )
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
### Create the body of a method that calls the callbacks of the given +hook+.
|
50
|
+
def self::make_hook_method( callbackset, **options )
|
51
|
+
return lambda do |*args|
|
52
|
+
set = self.public_send( callbackset ) or raise "No hook callback registration set!"
|
53
|
+
|
54
|
+
self.public_send( "#{callbackset}_run=", true )
|
55
|
+
|
56
|
+
set.to_a.each do |callback|
|
57
|
+
callback.call( *args )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
### Define a hook with the given +name+ that can be registered by calling the
|
64
|
+
### method of the same +name+ and then run by calling #call_<name>_hooks.
|
65
|
+
def define_hook( name, **options )
|
66
|
+
callbacks_name = "#{name}_callbacks"
|
67
|
+
self.instance_variable_set( "@#{callbacks_name}", Set.new )
|
68
|
+
self.singleton_attr_reader( callbacks_name )
|
69
|
+
self.instance_variable_set( "@#{callbacks_name}_run", false )
|
70
|
+
self.singleton_predicate_accessor( "#{callbacks_name}_run" )
|
71
|
+
|
72
|
+
register_body = Mixins::Hooks.
|
73
|
+
make_registration_method( callbacks_name, **options )
|
74
|
+
self.singleton_class.define_method( name, ®ister_body )
|
75
|
+
|
76
|
+
calling_body = Mixins::Hooks.
|
77
|
+
make_hook_method( callbacks_name, **options )
|
78
|
+
self.singleton_class.define_method( "call_#{name}_hook", &calling_body )
|
79
|
+
self.singleton_method_alias( "run_#{name}_hook", "call_#{name}_hook" )
|
80
|
+
end
|
81
|
+
|
82
|
+
end # module Mixins::Hooks
|
83
|
+
|
84
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'mixins' unless defined?( Mixins )
|
4
|
+
|
5
|
+
|
6
|
+
# An extensible #inspect.
|
7
|
+
module Mixins::Inspection
|
8
|
+
|
9
|
+
### Return a human-readable representation of the object suitable for debugging.
|
10
|
+
def inspect
|
11
|
+
details = self.inspect_details
|
12
|
+
details = ' ' + details unless details.empty? || details.start_with?( ' ' )
|
13
|
+
|
14
|
+
return "#<%p:#%x%s>" % [
|
15
|
+
self.class,
|
16
|
+
self.object_id,
|
17
|
+
details,
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
### Return the detail portion of the inspect output for this object.
|
23
|
+
def inspect_details
|
24
|
+
return ''
|
25
|
+
end
|
26
|
+
|
27
|
+
end # module Mixins::Inspection
|
28
|
+
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'mixins' unless defined?( Mixins )
|
4
|
+
|
5
|
+
|
6
|
+
# A collection of methods for declaring other methods.
|
7
|
+
#
|
8
|
+
# class MyClass
|
9
|
+
# extend Mixins::MethodUtilities
|
10
|
+
#
|
11
|
+
# singleton_attr_accessor :types
|
12
|
+
# singleton_method_alias :kinds, :types
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# MyClass.types = [ :pheno, :proto, :stereo ]
|
16
|
+
# MyClass.kinds # => [:pheno, :proto, :stereo]
|
17
|
+
#
|
18
|
+
module Mixins::MethodUtilities
|
19
|
+
|
20
|
+
### Creates instance variables and corresponding methods that return their
|
21
|
+
### values for each of the specified +symbols+ in the singleton of the
|
22
|
+
### declaring object (e.g., class instance variables and methods if declared
|
23
|
+
### in a Class).
|
24
|
+
def singleton_attr_reader( *symbols )
|
25
|
+
singleton_class.instance_exec( symbols ) do |attrs|
|
26
|
+
attr_reader( *attrs )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
### Create instance variables and corresponding methods that return
|
32
|
+
### true or false values for each of the specified +symbols+ in the singleton
|
33
|
+
### of the declaring object.
|
34
|
+
def singleton_predicate_reader( *symbols )
|
35
|
+
singleton_class.extend( Mixins::MethodUtilities )
|
36
|
+
singleton_class.attr_predicate( *symbols )
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
### Creates methods that allow assignment to the attributes of the singleton
|
41
|
+
### of the declaring object that correspond to the specified +symbols+.
|
42
|
+
def singleton_attr_writer( *symbols )
|
43
|
+
singleton_class.instance_exec( symbols ) do |attrs|
|
44
|
+
attr_writer( *attrs )
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
### Creates readers and writers that allow assignment to the attributes of
|
50
|
+
### the singleton of the declaring object that correspond to the specified
|
51
|
+
### +symbols+.
|
52
|
+
def singleton_attr_accessor( *symbols )
|
53
|
+
symbols.each do |sym|
|
54
|
+
singleton_class.__send__( :attr_accessor, sym )
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
### Create predicate methods and writers that allow assignment to the attributes
|
60
|
+
### of the singleton of the declaring object that correspond to the specified
|
61
|
+
### +symbols+.
|
62
|
+
def singleton_predicate_accessor( *symbols )
|
63
|
+
singleton_class.extend( Mixins::MethodUtilities )
|
64
|
+
singleton_class.attr_predicate_accessor( *symbols )
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
### Creates an alias for the +original+ method named +newname+.
|
69
|
+
def singleton_method_alias( newname, original )
|
70
|
+
singleton_class.__send__( :alias_method, newname, original )
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
### Create a reader in the form of a predicate for the given +attrname+.
|
75
|
+
def attr_predicate( attrname )
|
76
|
+
attrname = attrname.to_s.chomp( '?' )
|
77
|
+
define_method( "#{attrname}?" ) do
|
78
|
+
instance_variable_get( "@#{attrname}" ) ? true : false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
### Create a reader in the form of a predicate for the given +attrname+
|
84
|
+
### as well as a regular writer method.
|
85
|
+
def attr_predicate_accessor( attrname )
|
86
|
+
attrname = attrname.to_s.chomp( '?' )
|
87
|
+
attr_writer( attrname )
|
88
|
+
attr_predicate( attrname )
|
89
|
+
end
|
90
|
+
|
91
|
+
end # module Mixins::MethodUtilities
|
92
|
+
|
data/lib/mixins.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
|
4
|
+
# A collection of Modules that can be mixed into other modules to make
|
5
|
+
# common tasks easier and more intention-revealing.
|
6
|
+
module Mixins
|
7
|
+
|
8
|
+
# Package version
|
9
|
+
VERSION = '0.0.1'
|
10
|
+
|
11
|
+
|
12
|
+
autoload :MethodUtilities, 'mixins/method_utilities'
|
13
|
+
autoload :DataUtilities, 'mixins/data_utilities'
|
14
|
+
autoload :Delegation, 'mixins/delegation'
|
15
|
+
autoload :Hooks, 'mixins/hooks'
|
16
|
+
autoload :Inspection, 'mixins/inspection'
|
17
|
+
autoload :Datadir, 'mixins/datadir'
|
18
|
+
|
19
|
+
end # module Mixins
|
20
|
+
|