test-unit 2.2.0 → 2.3.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.
@@ -1,3 +1,26 @@
1
+ === 2.3.0 / 2011-04-17
2
+
3
+ * 13 enhancements
4
+ * improve Hash key sorting for diff.
5
+ * [#28928] support any characters in declarative style description.
6
+ [Daniel Berger]
7
+ * add Error#location and make #backtrace deprecated.
8
+ * make TestCase#passed? public.
9
+ * add result finished and pass assertion notifications.
10
+ * add TestSuite#passed? public.
11
+ * add XML test runner.
12
+ * add --output-file-descriptor option.
13
+ * measure elapsed time for each test.
14
+ * add --collector option.
15
+ * support test driven test.
16
+ [Haruka Yoshihara]
17
+ * add cleanup hook it runs between after test and before teardown.
18
+ * support recursive collection sort for diff.
19
+
20
+ * Thanks
21
+ * Daniel Berger
22
+ * Haruka Yoshihara
23
+
1
24
  === 2.2.0 / 2011-02-14
2
25
 
3
26
  * 22 enhancements
@@ -6,7 +29,7 @@
6
29
  * [test-unit-users-en:00035] make GC-able finished tests.
7
30
  [Daniel Berger]
8
31
  * use also COLUMNS environment variable to guess terminal width.
9
- * make delta for assert_in_delta optiona.
32
+ * make delta for assert_in_delta optional.
10
33
  [Nobuyoshi Nakada]
11
34
  * add assert_not_respond_to.
12
35
  [Nobuyoshi Nakada]
@@ -15,6 +15,7 @@ html/famfamfam-logo.png
15
15
  html/favicon.ico
16
16
  html/favicon.png
17
17
  html/favicon.svg
18
+ html/github-logo.png
18
19
  html/heading-mark.png
19
20
  html/heading-mark.svg
20
21
  html/index.html
@@ -44,8 +45,10 @@ lib/test/unit/collector/descendant.rb
44
45
  lib/test/unit/collector/dir.rb
45
46
  lib/test/unit/collector/load.rb
46
47
  lib/test/unit/collector/objectspace.rb
48
+ lib/test/unit/collector/xml.rb
47
49
  lib/test/unit/color-scheme.rb
48
50
  lib/test/unit/color.rb
51
+ lib/test/unit/data.rb
49
52
  lib/test/unit/diff.rb
50
53
  lib/test/unit/error.rb
51
54
  lib/test/unit/exceptionhandler.rb
@@ -58,9 +61,11 @@ lib/test/unit/priority.rb
58
61
  lib/test/unit/runner/console.rb
59
62
  lib/test/unit/runner/emacs.rb
60
63
  lib/test/unit/runner/tap.rb
64
+ lib/test/unit/runner/xml.rb
61
65
  lib/test/unit/testcase.rb
62
66
  lib/test/unit/testresult.rb
63
67
  lib/test/unit/testsuite.rb
68
+ lib/test/unit/testsuitecreator.rb
64
69
  lib/test/unit/ui/console/outputlevel.rb
65
70
  lib/test/unit/ui/console/testrunner.rb
66
71
  lib/test/unit/ui/emacs/testrunner.rb
@@ -68,6 +73,7 @@ lib/test/unit/ui/tap/testrunner.rb
68
73
  lib/test/unit/ui/testrunner.rb
69
74
  lib/test/unit/ui/testrunnermediator.rb
70
75
  lib/test/unit/ui/testrunnerutilities.rb
76
+ lib/test/unit/ui/xml/testrunner.rb
71
77
  lib/test/unit/util/backtracefilter.rb
72
78
  lib/test/unit/util/method-owner-finder.rb
73
79
  lib/test/unit/util/observable.rb
@@ -83,11 +89,13 @@ test/collector/test-descendant.rb
83
89
  test/collector/test-load.rb
84
90
  test/collector/test_dir.rb
85
91
  test/collector/test_objectspace.rb
92
+ test/fixtures/plus.csv
86
93
  test/run-test.rb
87
94
  test/test-assertions.rb
88
95
  test/test-attribute.rb
89
96
  test/test-color-scheme.rb
90
97
  test/test-color.rb
98
+ test/test-data.rb
91
99
  test/test-diff.rb
92
100
  test/test-emacs-runner.rb
93
101
  test/test-fixture.rb
data/README.txt CHANGED
@@ -50,6 +50,7 @@ Ruby license and PSF license.
50
50
  === Active
51
51
 
52
52
  * Kouhei Sutou: The current maintainer
53
+ * Haruka Yoshihara: Data driven test supports.
53
54
 
54
55
  === Inactive
55
56
 
data/Rakefile CHANGED
@@ -46,8 +46,7 @@ end
46
46
  desc "Tag the current revision."
47
47
  task :tag do
48
48
  message = "Released Test::Unit #{version}!"
49
- base = "svn+ssh://#{ENV['USER']}@rubyforge.org/var/svn/test-unit/"
50
- sh 'svn', 'copy', '-m', message, "#{base}trunk", "#{base}tags/#{version}"
49
+ sh 'git', 'tag', '-a', version, '-m', message
51
50
  end
52
51
 
53
52
  # vim: syntax=Ruby
Binary file
@@ -78,13 +78,18 @@ require "test/unit"</pre>
78
78
  </p>
79
79
  <h3 id="test-unit-latest">test-unit: The latest release</h3>
80
80
  <p>
81
- 2.2.0 is the latest release. It had been released at 2011-02-14.
81
+ 2.3.0 is the latest release. It had been released at 2011-04-17.
82
82
  </p>
83
83
  <h3 id="test-unit-install">test-unit: Install</h3>
84
84
  <p>
85
85
  Install:
86
86
  <pre class="command">% sudo gem install test-unit</pre>
87
87
  </p>
88
+ <p>
89
+ Usage:
90
+ <pre class="code">gem "test-unit"
91
+ require "test/unit"</pre>
92
+ </p>
88
93
 
89
94
  <h2 id="test-unit-full">test-unit-full</h2>
90
95
  <p>
@@ -125,7 +130,7 @@ require "test/unit"</pre>
125
130
  </p>
126
131
  <h3 id="test-unit-notify-latest">test-unit-notify: The latest release</h3>
127
132
  <p>
128
- 0.2.1 is the latest release. It had been released at 2011-02-10.
133
+ 0.3.0 is the latest release. It had been released at 2011-04-15.
129
134
  </p>
130
135
  <h3 id="test-unit-notify-install">test-unit-notify: Install</h3>
131
136
  <p>
@@ -228,23 +233,24 @@ require "test/unit"</pre>
228
233
 
229
234
  <h3 id="repository">Repositories</h3>
230
235
  <p>
231
- Test::Unit uses Subverseion repository on RubyForge. Here are a list to checkout each package.
232
- </p>
233
- <dl>
234
- <dt>test-unit</dt>
235
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/trunk test-unit</pre></dd>
236
- <dt>test-unit-full</dt>
237
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-full/trunk test-unit-full</pre></dd>
238
- <dt>test-unit-notify</dt>
239
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-notify/trunk test-unit-notify</pre></dd>
240
- <dt>test-unit-rr</dt>
241
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-rr/trunk test-unit-rr</pre></dd>
242
- <dt>test-unit-runner-gtk2</dt>
243
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-runner-gtk2/trunk test-unit-runner-gtk2</pre></dd>
244
- <dt>test-unit-runner-tk</dt>
245
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-runner-tk/trunk test-unit-runner-tk</pre></dd>
246
- <dt>test-unit-runner-fox</dt>
247
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-runner-fox/trunk test-unit-runner-fox</pre></dd>
236
+ Test::Unit uses <a href="https://github.com/test-unit/">git repository on GitHub</a>. Here is a list to get each source code.
237
+ </p>
238
+ <dt><a href="https://github.com/test-unit/test-unit/">test-unit</a></dt>
239
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit.git</pre></dd>
240
+ <dt><a href="https://github.com/test-unit/test-unit-full/">test-unit-full</a></dt>
241
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-full.git</pre></dd>
242
+ <dt><a href="https://github.com/test-unit/test-unit-notify/">test-unit-notify</a></dt>
243
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-notify.git</pre></dd>
244
+ <dt><a href="https://github.com/test-unit/test-unit-rr/">test-unit-rr</a></dt>
245
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-rr.git</pre></dd>
246
+ <dt><a href="https://github.com/test-unit/test-unit-capybara/">test-unit-capybara</a></dt>
247
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-capybara.git</pre></dd>
248
+ <dt><a href="https://github.com/test-unit/test-unit-runner-gtk2/">test-unit-runner-gtk2</a></dt>
249
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-runner-gtk2.git</pre></dd>
250
+ <dt><a href="https://github.com/test-unit/test-unit-runner-tk/">test-unit-runner-tk</a></dt>
251
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-runner-tk.git</pre></dd>
252
+ <dt><a href="https://github.com/test-unit/test-unit-runner-fox/">test-unit-runner-fox</a></dt>
253
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-runner-fox.git</pre></dd>
248
254
  </dl>
249
255
  </div>
250
256
 
@@ -265,6 +271,11 @@ require "test/unit"</pre>
265
271
  <img src="rubyforge.png" width="120" height="24" border="0" alt="Test::Unit is hosted on RubyForge.org." />
266
272
  </a>
267
273
  </p>
274
+ <p id="sponsor-github">
275
+ <a href="https://github.com/test-unit/">
276
+ <img src="github-logo.png" width="100" height="45" border="0" alt="GitHub's git repositories are used." />
277
+ </a>
278
+ </p>
268
279
  <p id="sponsor-tango">
269
280
  <a href="http://tango.freedesktop.org/">
270
281
  <img width="120" height="53" border="0" alt="Tango Desktop Project's icons are used." src="tango-logo.png" />
@@ -91,13 +91,18 @@ require "test/unit"</pre>
91
91
  </p>
92
92
  <h3 id="test-unit-latest">test-unit最新リリース</h3>
93
93
  <p>
94
- 2011-02-14にリリースされた2.2.0が最新リリースです。
94
+ 2011-04-17にリリースされた2.3.0が最新リリースです。
95
95
  </p>
96
96
  <h3 id="test-unit-install">test-unitのインストール</h3>
97
97
  <p>
98
98
  インストール:
99
99
  <pre class="command">% sudo gem install test-unit</pre>
100
100
  </p>
101
+ <p>
102
+ 使い方:
103
+ <pre class="code">gem "test-unit"
104
+ require "test/unit"</pre>
105
+ </p>
101
106
 
102
107
  <h2 id="test-unit-full">test-unit-full</h2>
103
108
  <p>
@@ -137,7 +142,7 @@ require "test/unit"</pre>
137
142
  </p>
138
143
  <h3 id="test-unit-notify-latest">test-unit-notify最新リリース</h3>
139
144
  <p>
140
- 2011-02-10にリリースされた0.2.1が最新リリースです。
145
+ 2011-04-15にリリースされた0.3.0が最新リリースです。
141
146
  </p>
142
147
  <h3 id="test-unit-notify-install">test-unit-notifyのインストール</h3>
143
148
  <p>
@@ -242,23 +247,25 @@ require "test/unit"</pre>
242
247
 
243
248
  <h3 id="repository">リポジトリ</h3>
244
249
  <p>
245
- RubyForge上のSubversionリポジトリを利用しています。チェックアウト方法は以下の通りです。
250
+ <a href="https://github.com/test-unit/">GitHub上のgitリポジトリ</a>を利用しています。ソースコードは以下のように取得できます。
246
251
  </p>
247
252
  <dl>
248
- <dt>test-unit</dt>
249
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/trunk test-unit</pre></dd>
250
- <dt>test-unit-full</dt>
251
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-full/trunk test-unit-full</pre></dd>
252
- <dt>test-unit-notify</dt>
253
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-notify/trunk test-unit-notify</pre></dd>
254
- <dt>test-unit-rr</dt>
255
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-rr/trunk test-unit-rr</pre></dd>
256
- <dt>test-unit-runner-gtk2</dt>
257
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-runner-gtk2/trunk test-unit-runner-gtk2</pre></dd>
258
- <dt>test-unit-runner-tk</dt>
259
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-runner-tk/trunk test-unit-runner-tk</pre></dd>
260
- <dt>test-unit-runner-fox</dt>
261
- <dd><pre class="command">% svn co http://test-unit.rubyforge.org/svn/extensions/test-unit-runner-fox/trunk test-unit-runner-fox</pre></dd>
253
+ <dt><a href="https://github.com/test-unit/test-unit/">test-unit</a></dt>
254
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit.git</pre></dd>
255
+ <dt><a href="https://github.com/test-unit/test-unit-full/">test-unit-full</a></dt>
256
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-full.git</pre></dd>
257
+ <dt><a href="https://github.com/test-unit/test-unit-notify/">test-unit-notify</a></dt>
258
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-notify.git</pre></dd>
259
+ <dt><a href="https://github.com/test-unit/test-unit-rr/">test-unit-rr</a></dt>
260
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-rr.git</pre></dd>
261
+ <dt><a href="https://github.com/test-unit/test-unit-capybara/">test-unit-capybara</a></dt>
262
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-capybara.git</pre></dd>
263
+ <dt><a href="https://github.com/test-unit/test-unit-runner-gtk2/">test-unit-runner-gtk2</a></dt>
264
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-runner-gtk2.git</pre></dd>
265
+ <dt><a href="https://github.com/test-unit/test-unit-runner-tk/">test-unit-runner-tk</a></dt>
266
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-runner-tk.git</pre></dd>
267
+ <dt><a href="https://github.com/test-unit/test-unit-runner-fox/">test-unit-runner-fox</a></dt>
268
+ <dd><pre class="command">% git clone https://github.com/test-unit/test-unit-runner-fox.git</pre></dd>
262
269
  </dl>
263
270
  </div>
264
271
 
@@ -279,6 +286,11 @@ require "test/unit"</pre>
279
286
  <img src="rubyforge.png" width="120" height="24" border="0" alt="ラングバプロジェクトはRubyForge.orgにホスティングしてもらっています。" />
280
287
  </a>
281
288
  </p>
289
+ <p id="sponsor-github">
290
+ <a href="https://github.com/milter-manager/">
291
+ <img src="github-logo.png" width="100" height="45" border="0" alt="GitHubの提供するgitリポジトリを利用しています。" />
292
+ </a>
293
+ </p>
282
294
  <p id="sponsor-tango">
283
295
  <a href="http://tango.freedesktop.org/">
284
296
  <img width="120" height="53" border="0" alt="Tango Desktop Projectのアイコンを利用しています。" src="tango-logo.png" />
@@ -244,17 +244,24 @@ div.sponsors p#sponsor-rubyforge
244
244
  right: 50px;
245
245
  }
246
246
 
247
- div.sponsors p#sponsor-tango
247
+ div.sponsors p#sponsor-github
248
248
  {
249
249
  position: absolute;
250
250
  top: 50px;
251
251
  right: 50px;
252
252
  }
253
253
 
254
+ div.sponsors p#sponsor-tango
255
+ {
256
+ position: absolute;
257
+ top: 105px;
258
+ right: 50px;
259
+ }
260
+
254
261
  div.sponsors p#sponsor-famfamfam
255
262
  {
256
263
  position: absolute;
257
- top: 118px;
264
+ top: 168px;
258
265
  right: 50px;
259
266
  padding-bottom: 50px;
260
267
  }
@@ -1507,23 +1507,50 @@ Message: <#{convert(object.message)}>
1507
1507
  ---------------
1508
1508
  EOM
1509
1509
  else
1510
+ inspector = Inspector.new(object)
1510
1511
  if use_pp
1511
1512
  begin
1512
1513
  require 'pp' unless defined?(PP)
1513
- if HashInspector.target?(object)
1514
- pp_target = HashInspector.new(object)
1515
- else
1516
- pp_target = object
1517
- end
1518
1514
  begin
1519
- return PP.pp(pp_target, '').chomp
1515
+ return PP.pp(inspector, '').chomp
1520
1516
  rescue NameError
1521
1517
  end
1522
1518
  rescue LoadError
1523
1519
  self.use_pp = false
1524
1520
  end
1525
1521
  end
1526
- object.inspect
1522
+ inspector.inspect
1523
+ end
1524
+ end
1525
+ end
1526
+
1527
+ class Inspector
1528
+ def initialize(object)
1529
+ @object = object
1530
+ @inspect_target = inspect_target
1531
+ end
1532
+
1533
+ alias_method :native_inspect, :inspect
1534
+ def inspect
1535
+ @inspect_target.inspect
1536
+ end
1537
+
1538
+ def pretty_print(q)
1539
+ @inspect_target.pretty_print(q)
1540
+ end
1541
+
1542
+ def pretty_print_cycle(q)
1543
+ @inspect_target.pretty_print_cycle(q)
1544
+ end
1545
+
1546
+ private
1547
+ def inspect_target
1548
+ if HashInspector.target?(@object)
1549
+ HashInspector.new(@object)
1550
+ elsif ArrayInspector.target?(@object)
1551
+ ArrayInspector.new(@object)
1552
+ else
1553
+ @object
1527
1554
  end
1528
1555
  end
1529
1556
  end
@@ -1533,14 +1560,6 @@ EOM
1533
1560
  def target?(object)
1534
1561
  object.is_a?(Hash) or object == ENV
1535
1562
  end
1536
-
1537
- def normalize(object)
1538
- if target?(object)
1539
- new(object)
1540
- else
1541
- object
1542
- end
1543
- end
1544
1563
  end
1545
1564
 
1546
1565
  def initialize(hash)
@@ -1567,13 +1586,52 @@ EOM
1567
1586
  end
1568
1587
 
1569
1588
  def pretty_print_cycle(q)
1570
- q.text(@hash.empty? ? '{}' : '{...}')
1589
+ @hash.pretty_print_cycle(q)
1571
1590
  end
1572
1591
 
1573
1592
  def each_pair
1574
- @hash.keys.sort.each do |key|
1575
- yield(self.class.normalize(key),
1576
- self.class.normalize(@hash[key]))
1593
+ keys = @hash.keys
1594
+ begin
1595
+ keys = keys.sort # FIXME: more cleverly
1596
+ rescue ArgumentError
1597
+ end
1598
+ keys.each do |key|
1599
+ yield(Inspector.new(key),
1600
+ Inspector.new(@hash[key]))
1601
+ end
1602
+ end
1603
+ end
1604
+
1605
+ class ArrayInspector
1606
+ class << self
1607
+ def target?(object)
1608
+ object.is_a?(Array)
1609
+ end
1610
+ end
1611
+
1612
+ def initialize(array)
1613
+ @array = array
1614
+ end
1615
+
1616
+ def inspect
1617
+ @array.inspect
1618
+ end
1619
+
1620
+ def pretty_print(q)
1621
+ q.group(1, '[', ']') do
1622
+ q.seplist(self) do |v|
1623
+ q.pp(v)
1624
+ end
1625
+ end
1626
+ end
1627
+
1628
+ def pretty_print_cycle(q)
1629
+ @array.pretty_print_cycle(q)
1630
+ end
1631
+
1632
+ def each
1633
+ @array.each do |element|
1634
+ yield(Inspector.new(element))
1577
1635
  end
1578
1636
  end
1579
1637
  end
@@ -1,6 +1,22 @@
1
1
  module Test
2
2
  module Unit
3
3
  module Attribute
4
+ class StringifyKeyHash < Hash
5
+ class << self
6
+ def stringify(object)
7
+ object.to_s
8
+ end
9
+ end
10
+
11
+ def [](key)
12
+ super(self.class.stringify(key))
13
+ end
14
+
15
+ def []=(key, value)
16
+ super(self.class.stringify(key), value)
17
+ end
18
+ end
19
+
4
20
  class << self
5
21
  def included(base)
6
22
  base.extend(BaseClassMethods)
@@ -34,9 +50,8 @@ module Test
34
50
  method_names << options
35
51
  options = {}
36
52
  end
37
- @current_attributes ||= {}
38
53
  if method_names.empty?
39
- @current_attributes[name] = options.merge(:value => value)
54
+ current_attributes[name] = options.merge(:value => value)
40
55
  else
41
56
  method_names.each do |method_name|
42
57
  set_attributes(method_name, {name => value})
@@ -44,23 +59,29 @@ module Test
44
59
  end
45
60
  end
46
61
 
62
+ def current_attributes
63
+ @current_attributes ||= StringifyKeyHash.new
64
+ end
65
+
66
+ def current_attribute(name)
67
+ current_attributes[name] || StringifyKeyHash.new
68
+ end
69
+
47
70
  def attributes_table
48
- @attributes_table ||= {}
71
+ @attributes_table ||= StringifyKeyHash.new
49
72
  super.merge(@attributes_table)
50
73
  end
51
74
 
52
75
  def set_attributes(method_name, new_attributes)
53
76
  return if new_attributes.empty?
54
- method_name = normalize_method_name(method_name)
55
- @attributes_table ||= {}
56
- @attributes_table[method_name] ||= {}
77
+ @attributes_table ||= StringifyKeyHash.new
78
+ @attributes_table[method_name] ||= StringifyKeyHash.new
57
79
  current_attributes = @attributes_table[method_name]
58
80
  new_attributes.each do |key, value|
59
- key = normalize_attribute_name(key)
60
81
  observers = attribute_observers(key) || []
61
82
  observers.each do |observer|
62
83
  observer.call(self,
63
- key,
84
+ StringifyKeyHash.stringify(key),
64
85
  (attributes(method_name) || {})[key],
65
86
  value,
66
87
  method_name)
@@ -70,7 +91,6 @@ module Test
70
91
  end
71
92
 
72
93
  def attributes(method_name)
73
- method_name = normalize_method_name(method_name)
74
94
  attributes = attributes_table[method_name]
75
95
  ancestors[1..-1].each do |ancestor|
76
96
  if ancestor.is_a?(Class) and ancestor < Test::Unit::Attribute
@@ -83,42 +103,26 @@ module Test
83
103
  break
84
104
  end
85
105
  end
86
- attributes
87
- end
88
-
89
- def get_attribute(method_name, attribute_name)
90
- attribute_name = normalize_attribute_name(attribute_name)
91
- (attributes(method_name) || {})[attribute_name]
106
+ attributes || StringifyKeyHash.new
92
107
  end
93
108
 
94
- @@attribute_observers = {}
109
+ @@attribute_observers = StringifyKeyHash.new
95
110
  def register_attribute_observer(attribute_name, observer=Proc.new)
96
- attribute_name = normalize_attribute_name(attribute_name)
97
111
  @@attribute_observers[attribute_name] ||= []
98
112
  @@attribute_observers[attribute_name] << observer
99
113
  end
100
114
 
101
115
  def attribute_observers(attribute_name)
102
- attribute_name = normalize_attribute_name(attribute_name)
103
116
  @@attribute_observers[attribute_name]
104
117
  end
105
-
106
- private
107
- def normalize_attribute_name(name)
108
- name.to_s
109
- end
110
-
111
- def normalize_method_name(name)
112
- name.to_s
113
- end
114
118
  end
115
119
 
116
120
  def attributes
117
- self.class.attributes(@method_name) || {}
121
+ self.class.attributes(@method_name) || StringifyKeyHash.new
118
122
  end
119
123
 
120
124
  def [](name)
121
- self.class.get_attribute(@method_name, name)
125
+ attributes[name]
122
126
  end
123
127
  end
124
128
  end