[前][次][番号順一覧][スレッド一覧]

ruby-changes:10767

From: nobu <ko1@a...>
Date: Sun, 15 Feb 2009 21:46:22 +0900 (JST)
Subject: [ruby-changes:10767] Ruby:r22332 (trunk, ruby_1_8): * lib/ostruct.rb (OpenStruct#new_ostruct_member): checks if frozen.

nobu	2009-02-15 21:43:46 +0900 (Sun, 15 Feb 2009)

  New Revision: 22332

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=22332

  Log:
    * lib/ostruct.rb (OpenStruct#new_ostruct_member): checks if frozen.
      [ruby-talk:328195], [ruby-core:22142]

  Modified files:
    branches/ruby_1_8/ChangeLog
    branches/ruby_1_8/lib/ostruct.rb
    branches/ruby_1_8/test/ostruct/test_ostruct.rb
    trunk/ChangeLog
    trunk/lib/ostruct.rb
    trunk/test/ostruct/test_ostruct.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 22331)
+++ ChangeLog	(revision 22332)
@@ -1,3 +1,8 @@
+Sun Feb 15 21:43:44 2009  Nobuyoshi Nakada  <nobu@r...>
+
+	* lib/ostruct.rb (OpenStruct#new_ostruct_member): checks if frozen.
+	  [ruby-talk:328195], [ruby-core:22142]
+
 Sun Feb 15 21:22:48 2009  Nobuyoshi Nakada  <nobu@r...>
 
 	* lib/test/unit/assertions.rb (Test::Unit::Assertions): aliases
Index: lib/ostruct.rb
===================================================================
--- lib/ostruct.rb	(revision 22331)
+++ lib/ostruct.rb	(revision 22332)
@@ -67,29 +67,33 @@
     @table.each_key{|key| new_ostruct_member(key)}
   end
 
+  def modifiable
+    if self.frozen?
+      raise TypeError, "can't modify frozen #{self.class}", caller(2)
+    end
+    @table
+  end
+  protected :modifiable
+
   def new_ostruct_member(name)
     name = name.to_sym
     unless self.respond_to?(name)
       class << self; self; end.class_eval do
         define_method(name) { @table[name] }
-        define_method(:"#{name}=") { |x| @table[name] = x }
+        define_method("#{name}=") { |x| modifiable[name] = x }
       end
     end
+    name
   end
 
   def method_missing(mid, *args) # :nodoc:
     mname = mid.id2name
     len = args.length
-    if mname =~ /=$/
+    if mname.chomp!('=')
       if len != 1
         raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
       end
-      if self.frozen?
-        raise TypeError, "can't modify frozen #{self.class}", caller(1)
-      end
-      mname.chop!
-      self.new_ostruct_member(mname)
-      @table[mname.intern] = args[0]
+      modifiable[new_ostruct_member(mname)] = args[0]
     elsif len == 0
       @table[mid]
     else
Index: test/ostruct/test_ostruct.rb
===================================================================
--- test/ostruct/test_ostruct.rb	(revision 22331)
+++ test/ostruct/test_ostruct.rb	(revision 22332)
@@ -34,4 +34,12 @@
     foo.bar.foo = foo
     assert_equal('#<OpenStruct bar=#<OpenStruct foo=#<OpenStruct ...>>>', foo.inspect)
   end
+
+  def test_frozen
+    o = OpenStruct.new
+    o.a = 'a'
+    o.freeze
+    assert_raise(TypeError) {o.b = 'b'}
+    assert_not_respond_to(o, :b)
+  end
 end
Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog	(revision 22331)
+++ ruby_1_8/ChangeLog	(revision 22332)
@@ -1,3 +1,8 @@
+Sun Feb 15 21:43:44 2009  Nobuyoshi Nakada  <nobu@r...>
+
+	* lib/ostruct.rb (OpenStruct#new_ostruct_member): checks if frozen.
+	  [ruby-talk:328195], [ruby-core:22142]
+
 Sun Feb 15 21:07:05 2009  Nobuyoshi Nakada  <nobu@r...>
 
 	* lib/ostruct.rb (OpenStruct#inspect): fixed the recursion check.
Index: ruby_1_8/lib/ostruct.rb
===================================================================
--- ruby_1_8/lib/ostruct.rb	(revision 22331)
+++ ruby_1_8/lib/ostruct.rb	(revision 22332)
@@ -67,28 +67,33 @@
     @table.each_key{|key| new_ostruct_member(key)}
   end
 
+  def modifiable
+    if self.frozen?
+      raise TypeError, "can't modify frozen #{self.class}", caller(2)
+    end
+    @table
+  end
+  protected :modifiable
+
   def new_ostruct_member(name)
     name = name.to_sym
     unless self.respond_to?(name)
-      meta = class << self; self; end
-      meta.send(:define_method, name) { @table[name] }
-      meta.send(:define_method, :"#{name}=") { |x| @table[name] = x }
+      class << self; self; end.class_eval do
+        define_method(name) { @table[name] }
+        define_method("#{name}=") { |x| modifiable[name] = x }
+      end
     end
+    name
   end
 
   def method_missing(mid, *args) # :nodoc:
     mname = mid.id2name
     len = args.length
-    if mname =~ /=$/
+    if mname.chomp!('=')
       if len != 1
         raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
       end
-      if self.frozen?
-        raise TypeError, "can't modify frozen #{self.class}", caller(1)
-      end
-      mname.chop!
-      self.new_ostruct_member(mname)
-      @table[mname.intern] = args[0]
+      modifiable[new_ostruct_member(mname)] = args[0]
     elsif len == 0
       @table[mid]
     else
Index: ruby_1_8/test/ostruct/test_ostruct.rb
===================================================================
--- ruby_1_8/test/ostruct/test_ostruct.rb	(revision 22331)
+++ ruby_1_8/test/ostruct/test_ostruct.rb	(revision 22332)
@@ -2,6 +2,21 @@
 require 'ostruct'
 
 class TC_OpenStruct < Test::Unit::TestCase
+  def assert_not_respond_to(object, method, message="")
+    _wrap_assertion do
+      full_message = build_message(message, <<EOT, object, object.class, method)
+<?>
+of type <?>
+expected not to respond_to\\?<?>.
+EOT
+      _wrap_assertion do
+        if object.respond_to?(method)
+          raise Test::Unit::AssertionFailedError, full_message, caller(5)
+        end
+      end
+    end
+  end
+
   def test_equality
     o1 = OpenStruct.new
     o2 = OpenStruct.new
@@ -34,4 +49,12 @@
     foo.bar.foo = foo
     assert_equal('#<OpenStruct bar=#<OpenStruct foo=#<OpenStruct ...>>>', foo.inspect)
   end
+
+  def test_frozen
+    o = OpenStruct.new
+    o.a = 'a'
+    o.freeze
+    assert_raise(TypeError) {o.b = 'b'}
+    assert_not_respond_to(o, :b)
+  end
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]