attic 0.4.0 → 0.5.2
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.
- data/CHANGES.txt +16 -0
- data/README.rdoc +15 -12
- data/Rakefile +8 -1
- data/attic.gemspec +5 -3
- data/lib/attic.rb +75 -59
- data/lib/attic/mixins.rb +66 -1
- data/try/01_mixins_tryouts.rb +1 -1
- data/try/10_attic_tryouts.rb +13 -0
- data/try/30_nometaclass_tryouts.rb +27 -5
- data/try/40_explicit_accessor_tryouts.rb +23 -0
- data/try/X1_metaclasses.rb +112 -0
- data/try/X2_extending.rb +27 -0
- metadata +9 -7
- data/lib/attic/mixins/object.rb +0 -67
data/CHANGES.txt
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
ATTIC, CHANGES
|
2
2
|
|
3
|
+
#### 0.5.2 (2010-02-15) ###############################
|
4
|
+
|
5
|
+
* CHANGE: Remove hanna dependency
|
6
|
+
|
7
|
+
#### 0.5.0 (2009-11-29) ###############################
|
8
|
+
|
9
|
+
* FIXED: Classes can now only be extended once
|
10
|
+
* FIXED: Don't define the same attic variable more then once
|
11
|
+
* FIXED: Don't define instance_variable method for objects which
|
12
|
+
don't already have one.
|
13
|
+
* CHANGE: attic_vars method is now attic_variables
|
14
|
+
* CHANGE: Won't define accessor methods if methods with the same
|
15
|
+
name already exist.
|
16
|
+
* ADDED: all_instance_variables method (for no metaclasses)
|
17
|
+
* ADDED: Explicit attic_variable_set and attic_variable_get methods
|
18
|
+
|
3
19
|
|
4
20
|
#### 0.4.0 (2009-07-17) ###############################
|
5
21
|
|
data/README.rdoc
CHANGED
@@ -1,23 +1,27 @@
|
|
1
|
-
= Attic - v0.
|
1
|
+
= Attic - v0.5
|
2
2
|
|
3
|
-
A place
|
4
|
-
|
5
|
-
== Alpha Notice
|
6
|
-
|
7
|
-
This library is fresh (est 2009-07-06) and barely tested. It's fun to use but not reliable yet.
|
3
|
+
A place to hide private instance variables in your Ruby objects.
|
8
4
|
|
9
5
|
== Example
|
10
6
|
|
11
7
|
require 'attic'
|
12
8
|
|
13
|
-
String
|
14
|
-
|
9
|
+
class String
|
10
|
+
extend Attic
|
11
|
+
attic :timestamp
|
12
|
+
end
|
15
13
|
|
16
14
|
a = "anything"
|
17
15
|
a.timestamp = "1980-11-18"
|
18
|
-
a.instance_variables
|
19
|
-
a.timestamp
|
20
|
-
|
16
|
+
a.instance_variables # => []
|
17
|
+
a.timestamp # 1980-11-18
|
18
|
+
|
19
|
+
a.attic_variables # => [:timestamp]
|
20
|
+
|
21
|
+
a.attic_variable_set :tags, [:a, :b, :c]
|
22
|
+
a.attic_variable_get :tags # [:a, :b, :c]
|
23
|
+
|
24
|
+
a.attic_variables # => [:timestamp, :tags]
|
21
25
|
|
22
26
|
== Some objects have no metaclasses
|
23
27
|
|
@@ -29,7 +33,6 @@ Symbol and Fixnum objects do not have metaclasses so instance variables are hidd
|
|
29
33
|
Via Rubygems, one of:
|
30
34
|
|
31
35
|
$ gem install attic
|
32
|
-
$ gem install delano-attic --source http://gems.github.com/
|
33
36
|
|
34
37
|
or via download:
|
35
38
|
* attic-latest.tar.gz[http://github.com/delano/attic/tarball/latest]
|
data/Rakefile
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake/clean'
|
3
3
|
require 'rake/gempackagetask'
|
4
|
-
require 'hanna/rdoctask'
|
5
4
|
require 'fileutils'
|
6
5
|
include FileUtils
|
7
6
|
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'hanna/rdoctask'
|
10
|
+
rescue LoadError
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
end
|
13
|
+
|
14
|
+
|
8
15
|
task :default => :package
|
9
16
|
|
10
17
|
# CONFIG =============================================================
|
data/attic.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
@spec = Gem::Specification.new do |s|
|
2
2
|
s.name = "attic"
|
3
3
|
s.rubyforge_project = "attic"
|
4
|
-
s.version = "0.
|
5
|
-
s.summary = "A place
|
4
|
+
s.version = "0.5.2"
|
5
|
+
s.summary = "A place to hide private instance variables in your Ruby objects."
|
6
6
|
s.description = s.summary
|
7
7
|
s.author = "Delano Mandelbaum"
|
8
8
|
s.email = "delano@solutious.com"
|
@@ -41,12 +41,14 @@
|
|
41
41
|
attic.gemspec
|
42
42
|
lib/attic.rb
|
43
43
|
lib/attic/mixins.rb
|
44
|
-
lib/attic/mixins/object.rb
|
45
44
|
try/01_mixins_tryouts.rb
|
46
45
|
try/10_attic_tryouts.rb
|
47
46
|
try/20_accessing_tryouts.rb
|
48
47
|
try/25_string_tryouts.rb
|
49
48
|
try/30_nometaclass_tryouts.rb
|
49
|
+
try/40_explicit_accessor_tryouts.rb
|
50
|
+
try/X1_metaclasses.rb
|
51
|
+
try/X2_extending.rb
|
50
52
|
)
|
51
53
|
|
52
54
|
s.has_rdoc = true
|
data/lib/attic.rb
CHANGED
@@ -6,67 +6,74 @@ require 'attic/mixins'
|
|
6
6
|
# A place to store instance variables.
|
7
7
|
#
|
8
8
|
module Attic
|
9
|
-
VERSION = '0.
|
9
|
+
VERSION = '0.5.2' unless defined?(VERSION)
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def attic_variables
|
13
|
+
self.class.attic_variables
|
14
|
+
end
|
15
|
+
alias_method :attic_vars, :attic_variables
|
16
|
+
def attic_variable? n
|
17
|
+
self.class.attic_variable? n
|
18
|
+
end
|
19
|
+
def attic_variable_set(n,v)
|
20
|
+
attic_variables << n unless attic_variable? n
|
21
|
+
if metaclass?
|
22
|
+
metaclass.instance_variable_set("@#{n}", v)
|
23
|
+
else
|
24
|
+
instance_variable_set("@___attic_#{n}", v)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
def attic_variable_get(n)
|
28
|
+
if metaclass?
|
29
|
+
metaclass.instance_variable_get("@#{n}")
|
30
|
+
else
|
31
|
+
instance_variable_get("@___attic_#{n}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
10
35
|
|
11
36
|
def self.included(o)
|
12
37
|
raise "You probably meant to 'extend Attic' in #{o}"
|
13
38
|
end
|
14
39
|
|
15
40
|
def self.extended(o)
|
41
|
+
# This class has already been extended.
|
42
|
+
return if o.ancestors.member? Attic::InstanceMethods
|
43
|
+
|
44
|
+
|
16
45
|
## NOTE: This is just a reminder for a more descerning way to
|
17
46
|
## include the meta methods, instead of using a global mixin.
|
18
47
|
##o.class_eval do
|
19
48
|
## include ObjectHelpers
|
20
49
|
##end
|
21
|
-
|
22
50
|
# Create an instance method that returns the attic variables.
|
51
|
+
o.send :include, Attic::InstanceMethods
|
52
|
+
#p [:extend, self, o]
|
53
|
+
|
54
|
+
o.metaclass.instance_variable_set("@attic_variables", [])
|
23
55
|
o.class_eval do
|
24
|
-
|
25
|
-
self
|
56
|
+
def self.inherited(o2)
|
57
|
+
#p [:inherit, self, o2]
|
58
|
+
attic_vars = self.attic_variables.clone
|
59
|
+
o2.metaclass.instance_variable_set("@attic_variables", attic_vars)
|
26
60
|
end
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
metametaclass.instance_variable_set("@attic", vars)
|
38
|
-
|
39
|
-
define_method(name) do
|
40
|
-
metaclass.instance_variable_get("@#{name}")
|
41
|
-
end
|
42
|
-
define_method("#{name}=") do |val|
|
43
|
-
metaclass.instance_variable_set("@#{name}", val)
|
61
|
+
if method_defined? :instance_variables
|
62
|
+
old_instance_variables = instance_method(:instance_variables)
|
63
|
+
define_method :instance_variables do
|
64
|
+
ret = old_instance_variables.bind(self).call.clone
|
65
|
+
ret.reject! { |v| v.to_s =~ /^@___?attic/ } # match 2 or 3 underscores
|
66
|
+
ret
|
67
|
+
end
|
68
|
+
define_method :all_instance_variables do
|
69
|
+
old_instance_variables.bind(self).call
|
70
|
+
end
|
44
71
|
end
|
45
72
|
end
|
46
|
-
}
|
47
73
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
# Add the attic variables named to the list. We use a
|
52
|
-
# variable with 3 underscores to prevent collisions.
|
53
|
-
vars = attic_vars << name
|
54
|
-
instance_variable_set("@___attic_vars", vars)
|
55
|
-
|
56
|
-
define_method(name) do
|
57
|
-
instance_variable_get("@__attic_#{name}")
|
58
|
-
end
|
59
|
-
define_method("#{name}=") do |val|
|
60
|
-
instance_variable_set("@__attic_#{name}", val)
|
61
|
-
end
|
62
|
-
define_method :instance_variables do |*args|
|
63
|
-
ret = super *args
|
64
|
-
ret.reject! { |v| v.to_s =~ /^@___?attic/ } # match 2 or 3 underscores
|
65
|
-
ret
|
66
|
-
end
|
67
|
-
end
|
68
|
-
}
|
69
|
-
|
74
|
+
|
75
|
+
end
|
76
|
+
|
70
77
|
|
71
78
|
# A class method for defining variables to store in the attic.
|
72
79
|
# * +junk+ is a list of variables names. Accessor methods are
|
@@ -85,15 +92,22 @@ module Attic
|
|
85
92
|
# * <tt>String#timestamp</tt> for setting the value
|
86
93
|
#
|
87
94
|
def attic *junk
|
88
|
-
#p [:attic, self, metaclass?]
|
89
95
|
return metaclass if junk.empty?
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
junk.each do |name|
|
97
|
+
next if attic_variable? name
|
98
|
+
self.attic_variables << name
|
99
|
+
|
100
|
+
unless method_defined? name
|
101
|
+
define_method(name) do
|
102
|
+
attic_variable_get name
|
103
|
+
end
|
104
|
+
end
|
105
|
+
unless method_defined? "#{name}="
|
106
|
+
define_method("#{name}=") do |val|
|
107
|
+
attic_variable_set name, val
|
108
|
+
end
|
109
|
+
end
|
95
110
|
end
|
96
|
-
|
97
111
|
attic_vars
|
98
112
|
end
|
99
113
|
|
@@ -102,16 +116,18 @@ module Attic
|
|
102
116
|
#
|
103
117
|
# String.extend Attic
|
104
118
|
# String.attic :timestamp
|
105
|
-
# String.
|
119
|
+
# String.attic_variables # => [:timestamp]
|
106
120
|
#
|
107
|
-
def
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
121
|
+
def attic_variables
|
122
|
+
a = self.metaclass.instance_variable_get("@attic_variables")
|
123
|
+
a ||= self.metaclass.instance_variable_set("@attic_variables", [])
|
124
|
+
a
|
125
|
+
end
|
126
|
+
alias_method :attic_vars, :attic_variables
|
127
|
+
|
128
|
+
def attic_variable?(n)
|
129
|
+
attic_variables.member? n
|
113
130
|
end
|
114
|
-
|
115
131
|
|
116
132
|
end
|
117
133
|
|
data/lib/attic/mixins.rb
CHANGED
@@ -1,3 +1,68 @@
|
|
1
|
+
class NoMetaClass < RuntimeError
|
2
|
+
end
|
1
3
|
|
2
|
-
|
4
|
+
# = Object
|
5
|
+
#
|
6
|
+
# These methods are copied directly from _why's metaid.rb.
|
7
|
+
# See: http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
|
8
|
+
class Object
|
9
|
+
|
10
|
+
# An Array of classes which do not have metaclasses.
|
11
|
+
NOMETACLASS = [Symbol, Fixnum].freeze
|
12
|
+
|
13
|
+
def nometaclass?
|
14
|
+
NOMETACLASS.member?(self)
|
15
|
+
end
|
16
|
+
|
17
|
+
def metaclass?
|
18
|
+
!NOMETACLASS.member?(self.class)
|
19
|
+
end
|
20
|
+
|
21
|
+
# A convenient method for getting the metaclass of the current object.
|
22
|
+
# i.e.
|
23
|
+
#
|
24
|
+
# class << self; self; end;
|
25
|
+
#
|
26
|
+
# NOTE: Some Ruby class do not have meta classes (see: NOMETACLASS).
|
27
|
+
# For these classes, this method returns the class itself. That means
|
28
|
+
# the instance variables will stored in the class itself.
|
29
|
+
def metaclass
|
30
|
+
if !self.metaclass?
|
31
|
+
raise NoMetaClass, self
|
32
|
+
else
|
33
|
+
class << self; self; end;
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Execute a block +&blk+ within the metaclass of the current object.
|
38
|
+
def meta_eval &blk; metaclass.instance_eval &blk; end
|
39
|
+
|
40
|
+
# Add an instance method called +name+ to metaclass for the current object.
|
41
|
+
# This is useful because it will be available as a singleton method
|
42
|
+
# to all subclasses too.
|
43
|
+
def meta_def name, &blk
|
44
|
+
meta_eval { define_method name, &blk }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add a class method called +name+ for the current object's class. This
|
48
|
+
# isn't so special but it maintains consistency with meta_def.
|
49
|
+
def class_def name, &blk
|
50
|
+
class_eval { define_method name, &blk }
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# A convenient method for getting the metaclass of the metaclass
|
55
|
+
# i.e.
|
56
|
+
#
|
57
|
+
# self.metaclass.metaclass
|
58
|
+
#
|
59
|
+
def metametaclass; self.metaclass.metaclass; end
|
60
|
+
|
61
|
+
def metameta_eval &blk; metametaclass.instance_eval &blk; end
|
62
|
+
|
63
|
+
def metameta_def name, &blk
|
64
|
+
metameta_eval { define_method name, &blk }
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
3
68
|
|
data/try/01_mixins_tryouts.rb
CHANGED
data/try/10_attic_tryouts.rb
CHANGED
@@ -5,6 +5,7 @@ tryouts "Basics" do
|
|
5
5
|
drill "can extend Attic", true do
|
6
6
|
class ::Worker
|
7
7
|
extend Attic
|
8
|
+
def kind() :true end
|
8
9
|
end
|
9
10
|
# 1.9 # 1.8
|
10
11
|
Worker.methods.member?(:attic) || Worker.methods.member?('attic')
|
@@ -25,6 +26,18 @@ tryouts "Basics" do
|
|
25
26
|
w.respond_to? :size
|
26
27
|
end
|
27
28
|
|
29
|
+
drill "can access attic attributes explicitly", 2 do
|
30
|
+
w = Worker.new
|
31
|
+
w.attic_variable_set :size, 2
|
32
|
+
w.attic_variable_get :size
|
33
|
+
end
|
34
|
+
|
35
|
+
drill "won't define a method if on already exists", :true do
|
36
|
+
Worker.attic :kind
|
37
|
+
a = Worker.new
|
38
|
+
a.kind
|
39
|
+
end
|
40
|
+
|
28
41
|
end
|
29
42
|
|
30
43
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
group "No Meta Class"
|
2
|
-
library :attic,
|
2
|
+
library :attic, "lib"
|
3
3
|
tryouts "Basics" do
|
4
4
|
|
5
5
|
dream :class, Array
|
@@ -13,13 +13,12 @@ tryouts "Basics" do
|
|
13
13
|
:any.metaclass
|
14
14
|
end
|
15
15
|
|
16
|
-
## NOTE: fails
|
17
16
|
drill "Symbol instances don't cross streams", [:roger, nil] do
|
18
17
|
Symbol.extend Attic
|
19
18
|
Symbol.attic :name
|
20
|
-
a = :
|
19
|
+
a, b = :symbol1, :symbol2
|
21
20
|
a.name = :roger
|
22
|
-
[a.name,
|
21
|
+
[a.name, b.name]
|
23
22
|
end
|
24
23
|
|
25
24
|
drill "metaclass? method exists", true do
|
@@ -28,7 +27,30 @@ tryouts "Basics" do
|
|
28
27
|
end
|
29
28
|
|
30
29
|
drill "metaclass? method is false for a Symbol", false do
|
31
|
-
:any.
|
30
|
+
:any.metaclass?
|
31
|
+
end
|
32
|
+
|
33
|
+
dream [:@___attic_name]
|
34
|
+
drill "A Symbol's attic vars appear in all_instance_variables" do
|
35
|
+
Symbol.extend Attic
|
36
|
+
Symbol.attic :name
|
37
|
+
a, b = :symbol1, :symbol2
|
38
|
+
a.name = :roger
|
39
|
+
a.all_instance_variables
|
40
|
+
end
|
41
|
+
|
42
|
+
dream []
|
43
|
+
drill "A Symbol's attic vars do not appear in instance_variables" do
|
44
|
+
Symbol.extend Attic
|
45
|
+
Symbol.attic :name
|
46
|
+
a, b = :symbol1, :symbol2
|
47
|
+
a.name = :roger
|
48
|
+
a.instance_variables
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
drill "knows attic variables", [:name] do
|
53
|
+
Symbol.attic_variables
|
32
54
|
end
|
33
55
|
|
34
56
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
group "Attic"
|
2
|
+
library :attic, "lib"
|
3
|
+
tryouts "Explicit accessors" do
|
4
|
+
|
5
|
+
setup do
|
6
|
+
class ::Worker
|
7
|
+
extend Attic
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
drill "can set value", 100 do
|
12
|
+
a = Worker.new
|
13
|
+
a.attic_variable_set :space, 100
|
14
|
+
a.attic_variable_get :space
|
15
|
+
end
|
16
|
+
|
17
|
+
drill "doesn't create accessor methods", false do
|
18
|
+
a = Worker.new
|
19
|
+
a.attic_variable_set :space, 100
|
20
|
+
a.respond_to? :space
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,112 @@
|
|
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
ADDED
@@ -0,0 +1,27 @@
|
|
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
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delano Mandelbaum
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-02-15 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description: A place
|
16
|
+
description: A place to hide private instance variables in your Ruby objects.
|
17
17
|
email: delano@solutious.com
|
18
18
|
executables: []
|
19
19
|
|
@@ -31,12 +31,14 @@ files:
|
|
31
31
|
- attic.gemspec
|
32
32
|
- lib/attic.rb
|
33
33
|
- lib/attic/mixins.rb
|
34
|
-
- lib/attic/mixins/object.rb
|
35
34
|
- try/01_mixins_tryouts.rb
|
36
35
|
- try/10_attic_tryouts.rb
|
37
36
|
- try/20_accessing_tryouts.rb
|
38
37
|
- try/25_string_tryouts.rb
|
39
38
|
- try/30_nometaclass_tryouts.rb
|
39
|
+
- try/40_explicit_accessor_tryouts.rb
|
40
|
+
- try/X1_metaclasses.rb
|
41
|
+
- try/X2_extending.rb
|
40
42
|
has_rdoc: true
|
41
43
|
homepage: http://github.com/delano/attic
|
42
44
|
licenses: []
|
@@ -45,7 +47,7 @@ post_install_message:
|
|
45
47
|
rdoc_options:
|
46
48
|
- --line-numbers
|
47
49
|
- --title
|
48
|
-
- A place
|
50
|
+
- A place to hide private instance variables in your Ruby objects.
|
49
51
|
- --main
|
50
52
|
- README.rdoc
|
51
53
|
require_paths:
|
@@ -65,9 +67,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
67
|
requirements: []
|
66
68
|
|
67
69
|
rubyforge_project: attic
|
68
|
-
rubygems_version: 1.3.
|
70
|
+
rubygems_version: 1.3.5
|
69
71
|
signing_key:
|
70
72
|
specification_version: 3
|
71
|
-
summary: A place
|
73
|
+
summary: A place to hide private instance variables in your Ruby objects.
|
72
74
|
test_files: []
|
73
75
|
|
data/lib/attic/mixins/object.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
class NoMetaClass < RuntimeError
|
2
|
-
end
|
3
|
-
|
4
|
-
# = Object
|
5
|
-
#
|
6
|
-
# These methods are copied directly from _why's metaid.rb.
|
7
|
-
# See: http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
|
8
|
-
class Object
|
9
|
-
|
10
|
-
# An Array of classes which do not have metaclasses.
|
11
|
-
NOMETACLASS = [Symbol, Fixnum].freeze
|
12
|
-
|
13
|
-
def metaclass?
|
14
|
-
#p [:metaclass?, self, !NOMETACLASS.member?(self)]
|
15
|
-
!NOMETACLASS.member?(self)
|
16
|
-
end
|
17
|
-
|
18
|
-
# FIX: metaclass should check self or self.class? ??? Check previous version
|
19
|
-
|
20
|
-
# A convenient method for getting the metaclass of the current object.
|
21
|
-
# i.e.
|
22
|
-
#
|
23
|
-
# class << self; self; end;
|
24
|
-
#
|
25
|
-
# NOTE: Some Ruby class do not have meta classes (see: NOMETACLASS).
|
26
|
-
# For these classes, this method returns the class itself. That means
|
27
|
-
# the instance variables will stored in the class itself.
|
28
|
-
def metaclass
|
29
|
-
#p [:metaclass, self, self.class, self.class.metaclass?]
|
30
|
-
if !self.class.metaclass?
|
31
|
-
raise NoMetaClass, self
|
32
|
-
else
|
33
|
-
class << self; self; end;
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Execute a block +&blk+ within the metaclass of the current object.
|
38
|
-
def meta_eval &blk; metaclass.instance_eval &blk; end
|
39
|
-
|
40
|
-
# Add an instance method called +name+ to metaclass for the current object.
|
41
|
-
# This is useful because it will be available as a singleton method
|
42
|
-
# to all subclasses too.
|
43
|
-
def meta_def name, &blk
|
44
|
-
meta_eval { define_method name, &blk }
|
45
|
-
end
|
46
|
-
|
47
|
-
# Add a class method called +name+ for the current object's class. This
|
48
|
-
# isn't so special but it maintains consistency with meta_def.
|
49
|
-
def class_def name, &blk
|
50
|
-
class_eval { define_method name, &blk }
|
51
|
-
end
|
52
|
-
|
53
|
-
|
54
|
-
# A convenient method for getting the metaclass of the metaclass
|
55
|
-
# i.e.
|
56
|
-
#
|
57
|
-
# self.metaclass.metaclass
|
58
|
-
#
|
59
|
-
def metametaclass; self.metaclass.metaclass; end
|
60
|
-
|
61
|
-
def metameta_eval &blk; metametaclass.instance_eval &blk; end
|
62
|
-
|
63
|
-
def metameta_def name, &blk
|
64
|
-
metameta_eval { define_method name, &blk }
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|