

rubyのirbでrubyのコードを2回以上loadすると失敗します。  
なぜなのでしょうか?

pythonだと

[code]

    
    import mymodule
    import importlib
    
    importlib.reload(mymodule) # 変更が反映される
    
    
[/code]

とするとモジュールの変更が反映されますが

rubyだとどうするのでしょうか?

[code]

    
    >> load "./big_step.rb" #2回目
    TypeError: superclass mismatch for class Number
    
    
[/code]

big_step.rb

[code]

    
    class Number < Struct.new(:value)
        def to_s
            return value.to_s
        end
    
        def evaluate(environment)
            self
        end
    
        def inspect
            return "<<#{self}>>"
        end
    end
    
    
    class Multiply < Struct.new(:left, :right)
        def to_s
            return "#{left} * #{right}"
        end
    
        def inspect
            return "<<#{self}>>"
        end
    
        def evaluate(environment)
            Number.new(left.evaluate(environment).value * right.environment(environment).value)
        end
    end
    
    class Add < Struct.new(:left, :right)
        def to_s
            return "#{left} + #{right}"
        end
    
        def inspect
            return "<<#{self}>>"
        end
    
        def evaluate(environment)
            Number.new(left.evaluate(environment).value + right.evaluate(environment).value)
        end
    end
    
    class Boolean < Struct.new(:value)
        def to_s
             value.to_s
        end
    
        def inspect
            "<<#{self}>>"
        end
    
        def evaluate(environment)
            self
        end
    end
    
    class LessThan < Struct.new(:left, :right)
        def to_s
            "#{left} < #{right}"
        end
    
        def inspect
            "<<#{self}>>"
        end
    
    end
    
    class Variable < Struct.new(:name)
        def to_s
            name.to_s
        end
    
        def inspect
            "<<#{self}>>"
        end
    
        def evaluate(environment)
            environment[name]
        end
    end
    
    class DoNothing
        def to_s
            "do-noting"
        end
    
        def inspect
            "<<#{self}>>"
        end
    
        def ==(other_statement)
            other_statement.instance_of?(DoNothing)
        end
    end
    
    
    class Assign < Struct.new(:name, :expression)
        def to_s
            "#{name} = #{expression}"
        end
    
        def inspect
            "<<#{self}>>"
        end
    
        def evaluate(environment)
            environment.merge({name => expression.evaluate(environment)})
        end
    end
    
    
    class If < Struct.new(:condition, :true_exe, :false_exe)
        def to_s
            "if (#{condition}) { #{true_exe} } else { #{false_exe} }"
        end
    
        def inspect
            "<<#{self}>>"
        end
    
        def evaluate(environment)
            case condition.evaluate(environment)
            when Boolean.new(true)
                true_exe.evaluate(environment)
            when Boolean.new(false)
                false_exe.evaluate(environment)
            end
        end
    end
    
    class Sequence < Struct.new(:first, :second)
        def to_s
            "#{first}; #{second}"
        end
    
        def inspect
            "<<#{self}>>"
        end
    
    
        def evaluate(environment)
            second.evaluate(first.evaluate(environment))
        end
    end
    
    
    class While < Struct.new(:condition, :body)
        def to_s
            "while (#{condition}) { #{body} }"
        end
    
        def inspect
            "<<#{self}>>"
        end
    
        def evaluate(environment)
            case condition.evaluate(environment)
            when Boolean.new(true)
                evaluate(body.evaluate(environment))
            when Boolean.new(false)
                environment
            end
        end
    end
    
    
    
    
[/code]


CC BY-SA 3.0
2015-06-25T14:21:37.707
11734
2015-08-22T03:33:18.253
2015-06-26T13:54:14.197
5246
5246
question
ruby python irb
irbで2回以上loadすると失敗する


2回loadすると`class Number <
Struct.new(:value)`が2回実行されますが、`Struct.new(:value)`はそれぞれ別のクラスを新しく生成して返すので、クラス定義を追加するときに間違ったスーパークラスを指定したことになりエラーが発生します。

[code]

    irb(main):001:0> Struct.new(:value)
    => #<Class:0x00000000aab338>
    irb(main):002:0> Struct.new(:value)
    => #<Class:0x00000000a9fb28>
    irb(main):003:0> Struct.new(:value)
    => #<Class:0x00000000a90790>
    irb(main):004:0> Struct.new(:value) == Struct.new(:value)
    => false
    
[/code]

<http://docs.ruby-lang.org/ja/1.9.3/doc/spec=2fdef.html#class>

> クラスが既に定義されているとき、さらに同じクラス名でクラス定義を書くとクラスの定義の追加になります。ただし、元のクラスと異なるスーパークラスを指定すると
> TypeError が発生します。
[code]

>     class Foo < Array
>       def foo
>       end
>     end
>  
>     # 定義を追加(スーパークラス Array を明示的に指定しても同じ)
>     class Foo
>       def bar
>       end
>     end
>  
>     # 間違ったスーパークラスを指定するとエラー
>     class Foo < String
>     end
>     # => superclass mismatch for class Foo (TypeError)
>  
[/code]


CC BY-SA 3.0
2015-06-25T14:46:48.997
11736
2015-06-25T14:52:44.033
2015-06-25T14:52:44.033
3639
3639
11734
answer


いくつか対策を考えました。

  1. Strict.newしたサブクラスを定数に入れて、1度だけ作成する。  
定数を作ってあるかはdefinde?でチェックします。

[code]     unless defined? Struct_value

      Struct_value = Struct.new(:value)
    end
    class Number < Struct_value
     # 以下略
    
[/code]

  2. クラスが定義されている場合は、未定義にしてから定義する。  
参照: <https://stackoverflow.com/questions/11503558/how-to-undefine-class-in-
ruby>  
参照: <http://www.iwazer.com/~iwazawa/diary/2013/05/ruby-remove-defined-
class.html>  
参照: <http://qiita.com/ogawatti/items/0e69125ef4155241f598>

[code]     if defined? Number

      Object.send(:remove_const, :Number)
    end
    class Number < Struct.new(:value)
     # 以下略
    
[/code]

  3. シングルトンなStructファクトリーを作る。  
コードは結構適当なので、参考程度にしてください。

[code]     require 'singleton'

    class StructFactory
      include Singleton
      def initialize
        @structs = {}
      end
      def [](*key)
        unless @structs.has_key?(key)
          @structs[key] = Struct.new(*key)
        end
        return @structs[key]
      end
      def self.[](*key)
        instance[*key]
      end
    end
    class Number < StructFactory[:value]
     # 以下略
    
[/code]


CC BY-SA 3.0
2015-08-22T03:33:18.253
14721
2015-08-22T03:33:18.253
2017-05-23T12:38:55.250
-1
7347
11734
answer