attic 0.9.0.pre.rc2 → 1.0.0.pre.RC2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -5
- data/README.md +3 -6
- data/attic.gemspec +1 -1
- data/lib/attic/class_methods.rb +2 -2
- data/lib/attic/core_ext.rb +1 -1
- data/lib/attic.rb +14 -13
- data/try/01_mixins_tryouts.rb +62 -14
- data/try/10_attic_tryouts.rb +38 -28
- metadata +3 -6
- data/try/X1_metaclasses.rb +0 -112
- data/try/X2_extending.rb +0 -27
- data/try/X3_nosingleton.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65eaa51d7ee74a1e97bef40a3cdb0c6cb8c78ca29e0cd8f8bb55e0cba641f664
|
4
|
+
data.tar.gz: fbc75d2a1063522b54edfc6d608a2f4599ac2b34c39a92aa400b138138f19cd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a54f4d47b2aa70d9a8d6ee30578d5c06360e9e5c2ffd3c5dfa196086b40122dfee3d84b079cbabd9a24076262b8d8b4521d50a649fe111c3f8f3b80d20945da
|
7
|
+
data.tar.gz: b06ab0a4a824c1536046f4d36ee0a42ce0e5315e214ef398955cf45f7046c56937d93333102044a1a4607fbe4780dd176d0377569126320e81f623c220527c16
|
data/Gemfile.lock
CHANGED
@@ -5,7 +5,7 @@ GEM
|
|
5
5
|
byebug (11.1.3)
|
6
6
|
coderay (1.1.3)
|
7
7
|
drydock (0.6.9)
|
8
|
-
json (2.7.
|
8
|
+
json (2.7.2)
|
9
9
|
language_server-protocol (3.17.0.3)
|
10
10
|
method_source (1.0.0)
|
11
11
|
parallel (1.24.0)
|
@@ -46,8 +46,7 @@ GEM
|
|
46
46
|
yard (0.9.36)
|
47
47
|
|
48
48
|
PLATFORMS
|
49
|
-
arm64-darwin-
|
50
|
-
ruby
|
49
|
+
arm64-darwin-22
|
51
50
|
|
52
51
|
DEPENDENCIES
|
53
52
|
byebug
|
@@ -57,7 +56,7 @@ DEPENDENCIES
|
|
57
56
|
tryouts (= 2.2.0.pre.RC1)
|
58
57
|
|
59
58
|
RUBY VERSION
|
60
|
-
ruby 3.
|
59
|
+
ruby 3.2.0p0
|
61
60
|
|
62
61
|
BUNDLED WITH
|
63
|
-
2.
|
62
|
+
2.4.12
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Attic - v1.0-RC1 (
|
1
|
+
# Attic - v1.0-RC1 (2024-04-01)
|
2
2
|
|
3
3
|
A place to hide private instance variables in your Ruby objects: in the attic.
|
4
4
|
|
@@ -11,6 +11,7 @@ Like, _why though_? Well sometimes you want to hide thing from the public interf
|
|
11
11
|
|
12
12
|
### Example
|
13
13
|
|
14
|
+
|
14
15
|
```ruby
|
15
16
|
require 'attic'
|
16
17
|
|
@@ -49,7 +50,7 @@ Like, _why though_? Well sometimes you want to hide thing from the public interf
|
|
49
50
|
|
50
51
|
### **Objects without singleton classes
|
51
52
|
|
52
|
-
Symbol, Integer, Float, TrueClass, FalseClass, NilClass, and
|
53
|
+
Symbol, Integer, Float, TrueClass, FalseClass, NilClass, and Integer are all objects that do not have singleton classes. TrueClass, FalseClass, and NilClass are all singletons themselves. Integer is a singleton of Integer.
|
53
54
|
|
54
55
|
These objects do not have metaclasses so the attic is hidden in the object itself.
|
55
56
|
|
@@ -139,10 +140,6 @@ which produced the same results for both.
|
|
139
140
|
]
|
140
141
|
```
|
141
142
|
|
142
|
-
## Credits
|
143
|
-
|
144
|
-
* (@delano) Delano Mandelbaum
|
145
|
-
|
146
143
|
|
147
144
|
## License
|
148
145
|
|
data/attic.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "attic"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "1.0.0-RC2"
|
4
4
|
s.summary = "When in doubt, store it in the attic"
|
5
5
|
s.description = "Attic: a place to hide metadata about the class or variable itself (e.g. SHA hash summaries)."
|
6
6
|
s.authors = ["Delano Mandelbaum"]
|
data/lib/attic/class_methods.rb
CHANGED
@@ -21,8 +21,8 @@ module Attic
|
|
21
21
|
# for the object. In either case, objects that cannot have
|
22
22
|
# cannot have a dedicated singleton class (e.g. nil, true,
|
23
23
|
# false) will raise a TypeError. We rescue this and add the
|
24
|
-
# object to the NoSingletonError list so we don't
|
25
|
-
#
|
24
|
+
# object to the NoSingletonError list so we don't keep
|
25
|
+
# trying to access its singleton class over and over.
|
26
26
|
!singleton_class.nil?
|
27
27
|
|
28
28
|
rescue TypeError
|
data/lib/attic/core_ext.rb
CHANGED
data/lib/attic.rb
CHANGED
@@ -101,7 +101,6 @@ require_relative "attic/instance_methods"
|
|
101
101
|
#
|
102
102
|
module Attic
|
103
103
|
VERSION = '0.9.0-RC1'.freeze unless defined?(VERSION)
|
104
|
-
attr_reader :all_attic_variables
|
105
104
|
|
106
105
|
# A convenince method at the class level for including
|
107
106
|
# ConstructMethods in the given object specifically.
|
@@ -121,8 +120,10 @@ module Attic
|
|
121
120
|
obj.include Attic::ClassMethods
|
122
121
|
end
|
123
122
|
|
123
|
+
# Friendly exception to say we're not to be included
|
124
|
+
#
|
124
125
|
def self.included(obj)
|
125
|
-
raise
|
126
|
+
raise RuntimeError, "Did you mean to `extend Attic`` in #{obj}"
|
126
127
|
end
|
127
128
|
|
128
129
|
def self.extended(obj)
|
@@ -165,8 +166,9 @@ module Attic
|
|
165
166
|
# * +names+ is a list of variables names. Accessor methods are
|
166
167
|
# created for each variable name in the list.
|
167
168
|
#
|
168
|
-
# Returns
|
169
|
-
# given
|
169
|
+
# Returns an Array of all attic variables for the current
|
170
|
+
# class unless no arguments are given in which case it
|
171
|
+
# returns its singleton.
|
170
172
|
#
|
171
173
|
# e.g.
|
172
174
|
#
|
@@ -178,12 +180,12 @@ module Attic
|
|
178
180
|
# * <tt>String#timestamp</tt> for setting the value
|
179
181
|
#
|
180
182
|
def attic(*names)
|
181
|
-
return
|
183
|
+
return singleton_class if names.empty?
|
182
184
|
|
183
185
|
names.each do |name|
|
184
186
|
next if attic_variable? name
|
185
187
|
|
186
|
-
self.
|
188
|
+
self.attic_variables << name
|
187
189
|
|
188
190
|
unless method_defined?(name)
|
189
191
|
define_method(name) do
|
@@ -198,7 +200,7 @@ module Attic
|
|
198
200
|
end
|
199
201
|
end
|
200
202
|
|
201
|
-
|
203
|
+
attic_variables # only after defining new attic vars
|
202
204
|
end
|
203
205
|
|
204
206
|
# Returns an Array of attic variables for the current class.
|
@@ -208,12 +210,11 @@ module Attic
|
|
208
210
|
# String.attic :timestamp
|
209
211
|
# String.attic_variables # => [:timestamp]
|
210
212
|
#
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
# alias attic_vars attic_variables
|
213
|
+
def attic_variables
|
214
|
+
a = attic.instance_variable_get('@attic_variables')
|
215
|
+
a ||= attic.instance_variable_set('@attic_variables', [])
|
216
|
+
a
|
217
|
+
end
|
217
218
|
|
218
219
|
def attic_variable?(name)
|
219
220
|
attic_variables.member? name
|
data/try/01_mixins_tryouts.rb
CHANGED
@@ -1,17 +1,65 @@
|
|
1
|
-
|
1
|
+
require_relative '../lib/attic'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#=>
|
3
|
+
#
|
4
|
+
# Tests for the Object mixins that Attic relies on.
|
5
|
+
#
|
6
|
+
|
7
|
+
## Has a valid NoMetaClass exception class
|
8
|
+
NoMetaClass < RuntimeError
|
9
|
+
#=> true
|
10
10
|
|
11
|
-
##
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
## Has a pre-populated array of built-ins without a metaclass
|
12
|
+
begin
|
13
|
+
Object::NOMETACLASS
|
14
|
+
rescue NameError => e
|
15
|
+
e.class
|
16
16
|
end
|
17
|
-
#=>
|
17
|
+
#=> NameError
|
18
|
+
|
19
|
+
## Has Object#metaclass method
|
20
|
+
Object.new.respond_to? :metaclass
|
21
|
+
#=> false
|
22
|
+
|
23
|
+
## Has Object#singleton_class method
|
24
|
+
Object.new.respond_to? :singleton_class
|
25
|
+
#=> true
|
26
|
+
|
27
|
+
## Object#singleton_class is a class
|
28
|
+
Object.new.singleton_class.class
|
29
|
+
#=> Class
|
30
|
+
|
31
|
+
## Object#singleton_class is a class
|
32
|
+
Object.new.singleton_class.object_id.class
|
33
|
+
#=> Integer
|
34
|
+
|
35
|
+
## Object#singleton_class is a class
|
36
|
+
a = Object.new
|
37
|
+
b = Object.new
|
38
|
+
a.singleton_class.object_id == b.singleton_class.object_id
|
39
|
+
#=> false
|
40
|
+
|
41
|
+
## Object#singleton_class is an Object class
|
42
|
+
Object.new.singleton_class.superclass
|
43
|
+
#=> Object
|
44
|
+
|
45
|
+
## Object#singleton_class is equivalent to `class << self; self; end;`
|
46
|
+
a = Object.new
|
47
|
+
a.singleton_class == (class << a; self; end)
|
48
|
+
#=> true
|
49
|
+
|
50
|
+
## Integer doesn't have a singleton_class
|
51
|
+
Integer.singleton_class?
|
52
|
+
#=> false
|
53
|
+
|
54
|
+
## Symbol doesn't have a singleton_class
|
55
|
+
Symbol.singleton_class?
|
56
|
+
#=> false
|
57
|
+
|
58
|
+
## Object has a singleton_class
|
59
|
+
Object.singleton_class?
|
60
|
+
#=> false
|
61
|
+
|
62
|
+
## Object#singleton_class is equivalent to Object#singleton_class
|
63
|
+
a = Object.new
|
64
|
+
a.singleton_class == a.singleton_class
|
65
|
+
#=> true
|
data/try/10_attic_tryouts.rb
CHANGED
@@ -1,41 +1,51 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require_relative '../lib/attic'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Tests for the Attic module
|
5
|
+
#
|
6
|
+
|
7
|
+
## A class we define can extend Attic
|
8
|
+
class ::ExampleClass
|
5
9
|
extend Attic
|
6
|
-
def kind() :
|
10
|
+
def kind() :unlikely_value end
|
7
11
|
end
|
8
|
-
|
9
|
-
Worker.methods.member?(:attic) || Worker.methods.member?('attic')
|
12
|
+
ExampleClass.methods.member?(:attic)
|
10
13
|
#=> true
|
11
|
-
|
12
|
-
##
|
14
|
+
|
15
|
+
## Trying to include Attic raises an exception
|
13
16
|
begin
|
14
|
-
class ::
|
17
|
+
class ::ExampleClass
|
15
18
|
include Attic
|
16
19
|
end
|
17
|
-
rescue =>
|
18
|
-
|
20
|
+
rescue => e
|
21
|
+
e.class
|
19
22
|
end
|
20
|
-
#=>
|
23
|
+
#=> RuntimeError
|
21
24
|
|
22
|
-
##
|
23
|
-
|
24
|
-
w =
|
25
|
-
#w.attic :size
|
26
|
-
p Worker.instance_methods(false)
|
27
|
-
p Worker.methods.sort
|
25
|
+
## Can define attic variables at class level
|
26
|
+
ExampleClass.attic :size
|
27
|
+
w = ExampleClass.new
|
28
28
|
w.respond_to? :size
|
29
|
-
#=> true
|
30
|
-
|
31
|
-
##
|
32
|
-
|
29
|
+
#=> true
|
30
|
+
|
31
|
+
## Accessing attic vars at the instance level fails
|
32
|
+
begin
|
33
|
+
w = ExampleClass.new
|
34
|
+
w.attic :size, 2
|
35
|
+
rescue => e
|
36
|
+
e.class
|
37
|
+
end
|
38
|
+
#=> NoMethodError
|
39
|
+
|
40
|
+
## Can access attic vars the long way though
|
41
|
+
w = ExampleClass.new
|
33
42
|
w.attic_variable_set :size, 2
|
34
43
|
w.attic_variable_get :size
|
35
44
|
#=> 2
|
36
|
-
|
37
|
-
##
|
38
|
-
|
39
|
-
|
45
|
+
|
46
|
+
## Won't clobber an existing method with the same name
|
47
|
+
## NOTE: But also won't tell you it didn't define the method
|
48
|
+
ExampleClass.attic :kind
|
49
|
+
a = ExampleClass.new
|
40
50
|
a.kind
|
41
|
-
#=> :
|
51
|
+
#=> :unlikely_value
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre.RC2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delano Mandelbaum
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -78,9 +78,6 @@ files:
|
|
78
78
|
- try/25_string_tryouts.rb
|
79
79
|
- try/30_nometaclass_tryouts.rb
|
80
80
|
- try/40_explicit_accessor_tryouts.rb
|
81
|
-
- try/X1_metaclasses.rb
|
82
|
-
- try/X2_extending.rb
|
83
|
-
- try/X3_nosingleton.rb
|
84
81
|
homepage: https://github.com/delano/attic
|
85
82
|
licenses:
|
86
83
|
- MIT
|
@@ -100,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
97
|
- !ruby/object:Gem::Version
|
101
98
|
version: 1.3.1
|
102
99
|
requirements: []
|
103
|
-
rubygems_version: 3.
|
100
|
+
rubygems_version: 3.4.12
|
104
101
|
signing_key:
|
105
102
|
specification_version: 4
|
106
103
|
summary: When in doubt, store it in the attic
|
data/try/X1_metaclasses.rb
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
# $ ruby tryouts/metaclasses.rb
|
2
|
-
|
3
|
-
class Object
|
4
|
-
|
5
|
-
# A convenient method for getting the metaclass of the current object.
|
6
|
-
# i.e.
|
7
|
-
#
|
8
|
-
# class << self; self; end;
|
9
|
-
#
|
10
|
-
def metaclass; class << self; self; end; end
|
11
|
-
|
12
|
-
# Execute a block +&blk+ within the metaclass of the current object.
|
13
|
-
def meta_eval &blk; metaclass.instance_eval &blk; end
|
14
|
-
|
15
|
-
# Add an instance method called +name+ to metaclass for the current object.
|
16
|
-
# This is useful because it will be available as a singleton method
|
17
|
-
# to all subclasses too.
|
18
|
-
def meta_def name, &blk
|
19
|
-
meta_eval { define_method name, &blk }
|
20
|
-
end
|
21
|
-
|
22
|
-
# Add a class method called +name+ for the current object's class. This
|
23
|
-
# isn't so special but it maintains consistency with meta_def.
|
24
|
-
def class_def name, &blk
|
25
|
-
class_eval { define_method name, &blk }
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
# A convenient method for getting the metaclass of the metaclass
|
30
|
-
# i.e.
|
31
|
-
#
|
32
|
-
# self.metaclass.metaclass
|
33
|
-
#
|
34
|
-
def metametaclass; self.metaclass.metaclass; end
|
35
|
-
|
36
|
-
def metameta_eval &blk; metametaclass.instance_eval &blk; end
|
37
|
-
|
38
|
-
def metameta_def name, &blk
|
39
|
-
metameta_eval { define_method name, &blk }
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
# Create an instance method
|
45
|
-
class NamedArray1
|
46
|
-
class_eval do
|
47
|
-
define_method(:name) do
|
48
|
-
:roger
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
p [1, NamedArray1.new.name]
|
53
|
-
|
54
|
-
# Create getter and setter instance methods
|
55
|
-
class NamedArray2
|
56
|
-
class_eval do
|
57
|
-
define_method(:name) do
|
58
|
-
instance_variable_get("@name")
|
59
|
-
end
|
60
|
-
define_method(:name=) do |val|
|
61
|
-
instance_variable_set("@name", val)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
a = NamedArray2.new
|
66
|
-
a.name = :roger
|
67
|
-
p [2, a.name, a.instance_variables]
|
68
|
-
|
69
|
-
# Create getter and setter instance methods,
|
70
|
-
# store instance variable in metaclass
|
71
|
-
class NamedArray3
|
72
|
-
class_eval do
|
73
|
-
define_method(:name) do
|
74
|
-
metaclass.instance_variable_get("@name")
|
75
|
-
end
|
76
|
-
define_method(:name=) do |val|
|
77
|
-
metaclass.instance_variable_set("@name", val)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
a = NamedArray3.new
|
82
|
-
a.name = :roger
|
83
|
-
p [3, a.name, a.instance_variables, a.metaclass.instance_variables]
|
84
|
-
|
85
|
-
# Create a module with the which puts the functionality
|
86
|
-
# in NamedArray3 into a class method.
|
87
|
-
module StorageArea
|
88
|
-
def store *junk
|
89
|
-
junk.each do |name|
|
90
|
-
class_eval do
|
91
|
-
define_method(name) do
|
92
|
-
metaclass.instance_variable_get("@#{name}")
|
93
|
-
end
|
94
|
-
define_method("#{name}=") do |val|
|
95
|
-
metaclass.instance_variable_set("@#{name}", val)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
class NamedArray4
|
102
|
-
extend StorageArea
|
103
|
-
store :name
|
104
|
-
end
|
105
|
-
a = NamedArray4.new
|
106
|
-
a.name = :roger
|
107
|
-
p [4, a.name, a.instance_variables, a.metaclass.instance_variables]
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
data/try/X2_extending.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
$:.unshift './lib'
|
2
|
-
require 'attic'
|
3
|
-
|
4
|
-
class A
|
5
|
-
extend Attic
|
6
|
-
attic :andy
|
7
|
-
end
|
8
|
-
|
9
|
-
class B < A
|
10
|
-
attic :size
|
11
|
-
end
|
12
|
-
|
13
|
-
class C
|
14
|
-
extend Attic
|
15
|
-
attic :third
|
16
|
-
end
|
17
|
-
|
18
|
-
a, b, c = A.new, B.new, C.new
|
19
|
-
|
20
|
-
a.andy, b.andy = 1, 2
|
21
|
-
|
22
|
-
p [a.respond_to?(:andy), b.respond_to?(:andy)] # true, true
|
23
|
-
p [a.andy, b.andy] # 1, 2
|
24
|
-
|
25
|
-
p [a.class.attic_vars, b.class.attic_vars, c.class.attic_vars]
|
26
|
-
|
27
|
-
|
data/try/X3_nosingleton.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# "".has_singleton_class? # => true
|
4
|
-
# :"".has_singleton_class? # => false
|
5
|
-
# 1.has_singleton_class? # =>
|
6
|
-
# nil.has_singleton_class? # => false
|
7
|
-
# NilClass.has_singleton_class? # => true
|
8
|
-
|
9
|
-
# members = ["", :food, 1, 1.00000001, nil, NilClass, true, TrueClass]
|
10
|
-
# members2 = members.clone
|
11
|
-
|
12
|
-
# members.each_with_index do |member, idx|
|
13
|
-
# puts "member: #{member.inspect}"
|
14
|
-
# member2 = members2[idx]
|
15
|
-
|
16
|
-
# member.has_a_dedicated_singleton_class? # => false
|
17
|
-
# member2.has_a_dedicated_singleton_class? # => false
|
18
|
-
# member.bestow_a_singleton_class!
|
19
|
-
# member.has_a_dedicated_singleton_class? # => true
|
20
|
-
# member2.has_a_dedicated_singleton_class? # => false
|
21
|
-
# member2.bestow_a_singleton_class!
|
22
|
-
# member2.has_a_dedicated_singleton_class? # => true
|
23
|
-
|
24
|
-
# member.singleton_class.object_id # => 600
|
25
|
-
# member2.singleton_class.object_id # => 700
|
26
|
-
|
27
|
-
# member.has_method?(:foo) # => false
|
28
|
-
# member.foo # => NoMethodError
|
29
|
-
# member.add_to_singleton_class(:foo)
|
30
|
-
# member.has_method?(:foo) # => true
|
31
|
-
# member.foo = :bar
|
32
|
-
# member.foo # => :bar
|
33
|
-
# member.foo.object_id # => 601
|
34
|
-
|
35
|
-
# member2.has_method?(:foo) # => false
|
36
|
-
# member2.foo # => NoMethodError
|
37
|
-
# member2.add_to_singleton_class(:foo)
|
38
|
-
# member2.has_method?(:foo) # => true
|
39
|
-
# member2.foo = :bar
|
40
|
-
# member2.foo # => :bar
|
41
|
-
# member2.foo.object_id # => 701
|
42
|
-
|
43
|
-
# member2.foo.object_id == member.foo.object_id # => false
|
44
|
-
# end
|