attic 0.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,9 @@
1
1
  ATTIC, CHANGES
2
2
 
3
+ #### 0.3.1 (2009-07-13) ###############################
4
+
5
+ CRIPES! I'd forgotten to update the gemspec.
6
+
3
7
 
4
8
  #### 0.3 (2009-07-11) ###############################
5
9
 
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "attic"
3
3
  s.rubyforge_project = "attic"
4
- s.version = "0.3"
4
+ s.version = "0.3.1"
5
5
  s.summary = "A place for Ruby objects to hide instance variables."
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
@@ -39,6 +39,15 @@
39
39
  README.rdoc
40
40
  Rakefile
41
41
  attic.gemspec
42
+ lib/attic.rb
43
+ lib/attic/mixins.rb
44
+ lib/attic/mixins/object.rb
45
+ try/01_mixins_tryouts.rb
46
+ try/10_attic_tryouts.rb
47
+ try/20_accessing_tryouts.rb
48
+ try/25_string_tryouts.rb
49
+ try/30_nometaclass_tryouts.rb
50
+ try/metaclasses.rb
42
51
  )
43
52
 
44
53
  s.has_rdoc = true
@@ -0,0 +1,83 @@
1
+
2
+ require 'attic/mixins'
3
+
4
+ # = Attic
5
+ #
6
+ # A place to store instance variables.
7
+ #
8
+ module Attic
9
+ VERSION = '0.3.1'
10
+
11
+ def self.included(o)
12
+ raise "You probably meant to 'extend Attic' in #{o}"
13
+ end
14
+
15
+ def self.extended(o)
16
+ ## NOTE: This is just a reminder for a more descerning way to
17
+ ## include the meta methods, instead of using a global mixin.
18
+ ##o.class_eval do
19
+ ## include ObjectHelpers
20
+ ##end
21
+
22
+ # Create an instance method that returns the attic variables.
23
+ o.class_eval do
24
+ define_method :attic_vars do
25
+ self.class.attic_vars
26
+ end
27
+ end
28
+ end
29
+
30
+ # A class method for defining variables to store in the attic.
31
+ # * +junk+ is a list of variables names. Accessor methods are
32
+ # created for each variable name in the list.
33
+ #
34
+ # Returns the list of attic variable names or if not junk was
35
+ # given, returns the metaclass.
36
+ #
37
+ # e.g.
38
+ #
39
+ # String.extend Attic
40
+ # String.attic :timestamp
41
+ #
42
+ # In this example, attic created two instance methods:
43
+ # * +String#timestamp+ for getting the value
44
+ # * +String#timestamp+ for setting the value
45
+ #
46
+ def attic *junk
47
+ return metaclass if junk.empty?
48
+
49
+ # Add the attic variables named to the list. Notice that we
50
+ # cheakily store this in the metameta class so as to not
51
+ # disturb the metaclass instance variables.
52
+ metametaclass.instance_variable_set("@attic", [attic_vars, *junk].flatten)
53
+
54
+ junk.each do |name|
55
+ class_eval do
56
+ define_method(name) do
57
+ metaclass.instance_variable_get("@#{name}")
58
+ end
59
+ define_method("#{name}=") do |val|
60
+ metaclass.instance_variable_set("@#{name}", val)
61
+ end
62
+ end
63
+ end
64
+
65
+ attic_vars
66
+ end
67
+
68
+ # Returns an Array of attic variables for the current class.
69
+ # e.g.
70
+ #
71
+ # String.extend Attic
72
+ # String.attic :timestamp
73
+ # String.attic_vars # => [:timestamp]
74
+ #
75
+ def attic_vars
76
+ metametaclass.instance_variable_get("@attic") || []
77
+ end
78
+
79
+
80
+ end
81
+
82
+ # - Module#instance_method returns an UnboundMethod
83
+ # - http://ruby-doc.org/core/classes/Module.html#M001659
@@ -0,0 +1,3 @@
1
+
2
+ require 'attic/mixins/object'
3
+
@@ -0,0 +1,57 @@
1
+
2
+ # = Object
3
+ #
4
+ # These methods are copied directly from _why's metaid.rb.
5
+ # See: http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
6
+ class Object
7
+
8
+ # An Array of classes which do not have metaclasses.
9
+ NOMETACLASS = [Symbol, Fixnum].freeze
10
+
11
+ # A convenient method for getting the metaclass of the current object.
12
+ # i.e.
13
+ #
14
+ # class << self; self; end;
15
+ #
16
+ # NOTE: Some Ruby class do not have meta classes (see: NOMETACLASS).
17
+ # For these classes, this method returns the class itself. That means
18
+ # the instance variables will stored in the class itself.
19
+ def metaclass;
20
+ if NOMETACLASS.member? self.class
21
+ self.class
22
+ else
23
+ class << self; self; end;
24
+ end
25
+ end
26
+
27
+ # Execute a block +&blk+ within the metaclass of the current object.
28
+ def meta_eval &blk; metaclass.instance_eval &blk; end
29
+
30
+ # Add an instance method called +name+ to metaclass for the current object.
31
+ # This is useful because it will be available as a singleton method
32
+ # to all subclasses too.
33
+ def meta_def name, &blk
34
+ meta_eval { define_method name, &blk }
35
+ end
36
+
37
+ # Add a class method called +name+ for the current object's class. This
38
+ # isn't so special but it maintains consistency with meta_def.
39
+ def class_def name, &blk
40
+ class_eval { define_method name, &blk }
41
+ end
42
+
43
+
44
+ # A convenient method for getting the metaclass of the metaclass
45
+ # i.e.
46
+ #
47
+ # self.metaclass.metaclass
48
+ #
49
+ def metametaclass; self.metaclass.metaclass; end
50
+
51
+ def metameta_eval &blk; metametaclass.instance_eval &blk; end
52
+
53
+ def metameta_def name, &blk
54
+ metameta_eval { define_method name, &blk }
55
+ end
56
+
57
+ end
@@ -0,0 +1,12 @@
1
+ group "Mixins"
2
+ library :attic, 'lib'
3
+
4
+ tryouts "Object" do
5
+ drill "has metaclass", 'Object' do
6
+ Object.new.metaclass.superclass.to_s
7
+ end
8
+
9
+ drill "has metametaclass", '#<Class:Object>' do
10
+ Object.new.metametaclass.superclass.to_s
11
+ end
12
+ end
@@ -0,0 +1,28 @@
1
+ group "Attic"
2
+ library :attic, "lib"
3
+ tryouts "Basics" do
4
+
5
+ drill "can extend Attic", true do
6
+ class ::Worker
7
+ extend Attic
8
+ end
9
+ Worker.methods.member? :attic
10
+ end
11
+
12
+ drill "can't include Attic raises exception", :exception, RuntimeError do
13
+ class ::Worker
14
+ include Attic
15
+ end
16
+ end
17
+
18
+ drill "can define attic attribute", true do
19
+ Worker.attic :size
20
+ w = Worker.new
21
+ #w.attic :size
22
+ stash :methods, w.methods.sort
23
+ stash :metamethods, Worker.methods.sort
24
+ w.respond_to? :size
25
+ end
26
+
27
+ end
28
+
@@ -0,0 +1,34 @@
1
+ group "Attic"
2
+ library :attic, "lib"
3
+ tryouts "Setting and Getting" do
4
+
5
+ setup do
6
+ class ::Worker
7
+ extend Attic
8
+ attic :size
9
+ end
10
+ end
11
+
12
+ drill "save an instance variable the long way", 'S&F' do
13
+ w = Worker.new
14
+ w.metametaclass.instance_variable_set '@mattress', 'S&F'
15
+ w.metametaclass.instance_variable_get '@mattress'
16
+ end
17
+
18
+ drill "save an instance variable the short way", :california_king do
19
+ w = Worker.new
20
+ w.size = :california_king
21
+ w.size
22
+ end
23
+
24
+ drill "new instances don't cross streams", nil do
25
+ w = Worker.new
26
+ w.size
27
+ end
28
+
29
+ drill "instance variables are hidden", [] do
30
+ w = Worker.new
31
+ w.metametaclass.instance_variable_set '@mattress', 'S&F'
32
+ w.instance_variables
33
+ end
34
+ end
@@ -0,0 +1,38 @@
1
+ group "Attic"
2
+ library :attic, "lib"
3
+ tryouts "String Setting and Getting" do
4
+
5
+ drill "String can extend Attic", true do
6
+ String.extend Attic
7
+ String.respond_to? :attic
8
+ end
9
+
10
+ drill "save an instance variable the long way", 'S&F' do
11
+ s = ""
12
+ s.metametaclass.instance_variable_set '@mattress', 'S&F'
13
+ s.metametaclass.instance_variable_get '@mattress'
14
+ end
15
+
16
+ drill "can create attributes", [:goodies] do
17
+ String.attic :goodies
18
+ end
19
+
20
+ drill "save an instance variable the short way", :california_king do
21
+ s = ""
22
+ s.goodies = :california_king
23
+ stash :ivars, s.instance_variables
24
+ stash :avars, s.attic_vars
25
+ s.goodies
26
+ end
27
+
28
+ drill "String instances don't cross streams", false do
29
+ String.extend Attic
30
+ String.attic :name
31
+ a = "any"
32
+ a.name = :roger
33
+ a.name == "".name
34
+ end
35
+
36
+
37
+
38
+ end
@@ -0,0 +1,24 @@
1
+ group "No Meta Class"
2
+ library :attic, 'lib'
3
+ tryouts "Basics" do
4
+
5
+ dream :class, Array
6
+ dream [Symbol, Fixnum]
7
+ drill "has list of no metaclass classes" do
8
+ Object::NOMETACLASS
9
+ end
10
+
11
+ drill "Symbol metaclass returns Symbol", Symbol do
12
+ :any.metaclass
13
+ end
14
+
15
+ ## NOTE: fails
16
+ drill "Symbol instances don't cross streams", true do
17
+ Symbol.extend Attic
18
+ Symbol.attic :name
19
+ a = :any
20
+ a.name = :roger
21
+ [a.name, :another.name]
22
+ end
23
+
24
+ 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
+
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.3"
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-12 00:00:00 -04:00
12
+ date: 2009-07-13 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -29,6 +29,15 @@ files:
29
29
  - README.rdoc
30
30
  - Rakefile
31
31
  - attic.gemspec
32
+ - lib/attic.rb
33
+ - lib/attic/mixins.rb
34
+ - lib/attic/mixins/object.rb
35
+ - try/01_mixins_tryouts.rb
36
+ - try/10_attic_tryouts.rb
37
+ - try/20_accessing_tryouts.rb
38
+ - try/25_string_tryouts.rb
39
+ - try/30_nometaclass_tryouts.rb
40
+ - try/metaclasses.rb
32
41
  has_rdoc: true
33
42
  homepage: http://github.com/delano/attic
34
43
  licenses: []