IronRuby の使い方

 [Home] /  [Mirror] | IronRubyの応用 | Windows Forms | Office とデータベース | 実用 IronRuby スクリプト集 | FormMaker (自家製クラス)

投稿 2015/02/24 (Mirrorの投稿は2011/12)

はじめに

IronRubyとは

IronRuby とは ruby言語の一種で、Microsoft .NET Framework 上で動作するスクリプト言語です。WSHで動作する VBScript や JScript の代替に向いています。


特徴


実行


IronRubyスクリプトをインタプリタ指定なしで実行するには?


 

基本

簡単なプログラム(文字コードの指定)

デフォルトでは文字コードは'US-ASCII'とみなされるので、先頭に文字コードを指定しないと文字化けします。

# coding: SJIS
require "System"
# class
class Ruby
  def initialize
    @name = "Ruby"
  end
  
  def ToString()
    return " シフトJISコード"
  end
end
a = Ruby.new
puts(a.ToString())

上の例では "# coding: SJIS" としてシフトJISコードを指定しています。あるいは、"# coding: Windows-31J"としてもよいが、これらには微妙な違いがあるらしいです。

下の画像は上のサンプルコードの実行例です。


アセンブリの使用

.NET Frameworkのアセンブリ (DLL) を使用するには、requireを使用する。また、名前空間を正確に指定する必要があります。

# coding: SJIS
require "System"
System::Console::WriteLine('require "System" と System::Console::が必要。')

System::Console::を毎回指定するには面倒です。これを避ける方法はいくつかあります。

moduleを使う方法ですが、下のような漢字で、コードを挟みます。これでDictionaryクラスにSystem::Collections::Genericをつけなくてすみます。

require "System"
module System; module Collections; module Generic
dic = Dictionary[String, String].new
dic.Add("a", "A")
dic.Add("b", "AB")
dic.Add("c", "ABC")
dic.Add("d", "ABCD")
dic.keys().each do |x|
  puts x + "=>" + dic[x]
end
end;end;end

includeを使う方法は、下のようにincludeに名前空間を指定します。こちらのほうがC#のusingみたいで見栄えはいいです(落とし穴に気をつければ)。

require "System"
include System::Collections::Generic
dic = Dictionary[String, String].new
dic.Add("a", "A")
dic.Add("b", "AB")
dic.Add("c", "ABC")
dic.Add("d", "ABCD")
dic.keys().each do |x|
  puts x + "=>" + dic[x]
end

変数に代入する方法は、下のように名前空間を単純に代入して使います。

con = System::Console
con.ForegroundColor = 10
con.WriteLine("Green")

requireはC#の場合で言えば、「参照設定」(Visual Studioのプロジェクトエクスプローラで指定するアセンブリ)、includeはusingに相当します。


requireはC#の場合で言えば、「参照設定」(Visual Studioのプロジェクトエクスプローラで指定するアセンブリ)、includeはusingに相当します。


.NETか?rubyのクラスか?

どちらのクラスを使っているか、意識しておく必要があります。classメソッドを使うとクラス名が表示されます。

# coding: sjis
# どっちのクラス?
require "System"
puts Time.class
puts Time.now
puts System::DateTime.Now.class
puts System::DateTime.Now.ToString()

ところで、rubyでは大文字で始まる識別子は「定数」ということになっています。でも、.NETのメソッドやプロパティに関しては例外です。

この例で、ToString()メソッドをtoString()とするとエラーになります。


変数埋め込み

こんなのが動くか確認してみました。#{} を使うのもできるはず。

# coding: sjis
s = "りんご100個"
i = 100
a = "円のはいくら?"
a << " 一万円" << "です。"
puts a

クロージャー

rubyでは、引数付きブロックとか呼ばれますが、当然、IronRubyでも使えます。

10.times do |i|
  puts i
end

Generic

前の例ですでに出ていますが、C#でよく使うものとしてGenericがあります。そもそもrubyには型宣言がないので、Genericのような文法はrubyにはないはずです。でも、IronRubyでは[ ]で型を囲むことによりGenericを実現しています。

require "System"
include System::Collections::Generic
list = List[String].new
list.Add("A")
list.Add("AB")
list.Add("ABC")
list.Add("ABCD")
list.each do |x|
  puts x
end

ただ、C#のプログラムを移植するなどの場合を除けば、あまり使わないかもしれませんが。


メソッドのオーバーロード

rubyはメソッドのパラメータに型の指定がないので、メソッドのオーバーロードはC#と同じようにできません(区別がつかないため)。代わりに、変数の数や型を調べることにより、メソッドのオーバーロードと同じようなことを実現できます。その際、引数として*argsを使うと便利です。これはメソッドへ渡されたパラメータの配列です。

# coding: sjis
# 第一引数が文字列なら第二引数の数だけ連結。
# 第一引数が数なら第二引数をかける。
# 第二引数が省略されたときは、第二引数が2であるとみなす。
def times(*args)
  if args.size == 1 then
    if args[0].class == String then
      return args[0] + args[0]
    else
      return args[0] * 2
    end
  else
    if args[0].class == String then
      s = ""
      args[1].times do |i|
        s += args[0]
      end
      return s
    else
      return args[0] * args[1]
    end
  end
end
puts times('Abc', 5)
puts times(4, 5).to_s
puts times('Abc')
puts times(4).to_s

名前付き引数

名前つきの引数は、Visual Basicは前から可能でしたが、C#も4.0になるまできなかったです。rubyではperlと同じように、似た機能を連想配列で実現するするようです。

前のメソッドのオーバーロードのときと同じように、*argsを引数としその数と型を判別し、パラメータの値を連想配列の値として取得します。

# coding: sjis
#  第一引数が文字列なら第二引数の数だけ連結。
#  第一引数が数なら第二引数をかける。
def times(*args)
  if args.size == 1 and args[0].class == Hash then
    hash = args[0]
    v = hash[:v]
    n = hash[:n]
  else
    v = args[0]
    n = args[1]
  end
  if v.class == String then
     s = ""
     n.times do |i|
       s += args[0]
     end
     return s
  else
     return v * n
  end
end
puts times('Abc', 5)
puts times(4, 5).to_s

特異クラスの使用

特異クラスは、クラスの代わりにオブジェクトを継承したクラスです。C#の拡張メソッドと機能的にほぼ同じものです。

下の例では、System::ObjectのオブジェクトobjのメソッドToString()のオーバーライドとHello()メソッドの追加を行っています。

obj = System::Object.new
class << obj
  def ToString()
    return "an object"
  end
  
  def Hello()
    puts "Hello"
  end
end
puts obj.ToString()
obj.Hello()

public/protected/private

rubyではメソッドはデフォルトでpublicです。

publicはC#などと同じ意味ですが、protectedとprivateはC#などとは意味が異なります。rubyではこれらはどちらも似た意味で、C#でいうprivateに近いです。違いはprivateは関数形式(つまりオブジェクト.メソッドの形式でなく、ドットの左側つまりオブジェクトの部分を省略した形式)のみで呼び出すことができるというものです。

したがって、protectedメソッドでも派生クラスでそのメソッドを呼び出すとエラーになります。 p private, protectedの宣言は一度すると、publicが現れるまで有効です。下の例で、メソッドaとbはprivateです。

(例)

private
def a()

end

def b()

end

public

クラスのプロパティ

クラスのプロパティの書き方ですが、単純にインスタンス変数の読み書きをするだけなら、attr_accessor(attr_reader, attr_writer) を使って外部からアクセスできるようにします。

単純な読み書き以外をするなら、メソッドとして実装します。書き込みプロパティは

def  name=(value)
  @name = value
end

のようにします。

(サンプル)

class Rect
  def initialize(x=0, y=0, width=0, height=0)
    @x = x
    @y = y
    @width = width
    @height = height
  end
  attr_accessor :x
  attr_accessor :y
  attr_accessor :width
  attr_accessor :height
  def left
    return @x
  end
  def left=(value)
    @x = value
  end
  def top
    return @y
  end
  def top=(value)
    @y = value
  end
  def right
    return @x + @width
  end
  def bottom
    return @y + @height
  end
  def to_s
    return "x=#{@x}, y=#{@y}, width=#{@width}, height=#{@height}"
  end
end
r = Rect.new(10, 5, 30, 20)
puts r.to_s
r.left = 100
puts "x=" + r.x.to_s
puts "left=" + r.left.to_s

TryParse

文字列を数値に変換するとき、TryParseメソッドを使うことがよくあります。ところが、このメソッドの第二パラメータにはout修飾子が付いています。rubyにはout修飾子がないので、次のサンプルのようにします。

\include System
for s in ['123', 'ABC', '-109', '10e2']
  (result, i) = Int32::TryParse(s)
  if result then
    Console.WriteLine(i)
  else
    Console.WriteLine('Error : ' + s)
  end
end

引数の参照渡し

メソッドの引数は常に値渡しです。ただし、オブジェクトのメンバー変数(プロパティ)を変更すると、メソッドから戻った時、そのメンバー変数は参照渡しのように変更されます。

したがって、オブジェクトのメンバー変数を変更することにより参照による値の変更のように動作させることができます。

また、メソッドは複数の結果を返すことができるので、その機能を使うことで参照渡しと同じことができます。

def func(x, y)
  x += 1
  return x == y, x
end
(result, value) = func(10, 5)
p result
p value

このサンプルを実行すると

C:\workspace\IronRuby\test>ir ir_refparam.rb
false
11

のように表示されます。


Procオブジェクト (無名関数や繰り返しブロック)

Procクラスを使うと無名関数(メソッド)や繰り返しブロックを作れます。組み込み関数procはProc.newと同じなので、下の例ではprocを使用します。

# coding: Windows-31J
# 繰り返しブロックとしての利用
def pr
  for i in 1..5
    j = i - 1
    proc.call(i, j)
  #  次のようにしても同じ。ただし、yieldは引数の数のチェックを行わない。
  #    yield i, j
  end
end
pr do |x, y|
  puts x.to_s + " " + y.to_s
end
# 無名関数としての利用
x = 1
f = proc {
  x += 10
}
f.call
p x
# lambdaはprocと同じ(別名)
# この例では、yを引数として与えている。
f = lambda {|y|
  x -= y
}
f[5]  # f.call(5)の別名
p x

Delegate

rubyにもDelegateというのがありますが、C#のDelegateとは全く違います。

rubyのDelegateは、クラスの継承やモジュールの包含と似たような機能を「委譲」により実現するものです。

つまり、あるクラスに別のクラスのインスタンス(インスタンス変数として)があるとき、そのインスタンスへ特定の操作(つまりメソッド)を委譲するものです。

この委譲を実現するものは2つあり、ひとつはforwadable、もうひとつがdelegateです。前者は特定のメソッド(選択して)のみ委譲し、後者はほとんどのメソッドを委譲します。


次のサンプルは、下請けクラスがある製品(部品)を作って、元請けがそれをそのまま転売して儲けるというありがちな例です。

最初の方は、forwadableを使っています。元請けがbuhin_seisakuを下請けに委譲しています。

require 'forwardable'
class Shitauke
  def initialize
    @parts = {1=>'case', 2=>'pu', 3=>'pwb'}
  end
  def buhin_seisaku(part)
    return @parts[part]
  end
end

class Motouke
  extend Forwardable
  def initialize
    @shitauke = Shitauke.new
  end
  def_delegator :@shitauke, :buhin_seisaku, :choutatsu
end

buhin = []
moto = Motouke.new
buhin.push(moto.choutatsu(1))
buhin.push(moto.choutatsu(2))
buhin.each do |i|
  puts i
end

2番目の例は、元請けがまるごと下請けにseisakuを委譲しています。この例では、seisakuメソッドしかありませんが、kensaメソッドやhanbaiメソッドもあれば、それもいっしょに移譲されます。

require "delegate"
class Shitauke
  def initialize
    @parts = {1=>'case', 2=>'pu', 3=>'pwb'}
  end
  def seisaku(part)
    return @parts[part]
  end
end
class Motouke < DelegateClass(Shitauke)
  def initialize
    super(Shitauke.new)
  end
end
moto = Motouke.new
puts moto.seisaku(2)
puts moto.seisaku(3)

Rubyの種々の記法

rubyはUnix ShellやPerl風の記法があり、C#などしか知らないとちょっと戸惑うことがあります。

%記法

$変数

$で始まる変数はグローバル変数ですが、既定のグローバル変数がいろいろあります。

(例)

コマンド実行

` で囲まれたものは、コマンドとして実行されます。%x!String!と同じです。結果は文字列として返されます。

(例)

`ls -la /home/user`

シンボル

:で始まる文字列はシンボルと呼ばれて、連想配列のキーなどによく使われます。シンボルは文字列に変換できます。文字列は変数名、識別子、演算子のどれかです。

:left

ヒアドキュメント

C#では、@"..."で書くことができます。rubyでは <<文字列...文字列と書きます。

(例)

<<EOS
 ....
EOS

数値リテラル

?で始まるシーケンスは数値リテラルです。特殊文字コードなどを表すのに使われます。

(例)


moduleの使い方

moduleはVisual BasicのModule (C#のstaticクラス) に似ていますが、他のクラスに包含してそのクラスの一部のように使えます。また、モジュールのメソッドはデフォルトでは非公開です。ただし、クラスに包含するとデフォルトで公開になります。

モジュール単体で使う場合、メソッドを公開するには、module_functionで公開するメソッドを指定する必要があります。

(例) module_functionの使用例

module Module1
  def substr(str, start, length)
    return str[start, length]
  end
  def substring(str, startp, endp)
    return str[startp, endp - startp + 1]
  end
  module_function :substr
  module_function :substring
end
str = 'ABCDEFG'
puts Module1.substr(str, 1, 3)
puts Module1.substring(str, 0, 1)

モジュールを他のクラスに包含するには、includeを使います。クラスに包含されたモジュールのメソッドはデフォルトで公開になります。

(例) includeの使用例

module Module1
  def substr(str, start, length)
    return str[start, length]
  end
end
class Class1
  \include Module1
  def substring(str, startp, endp)
    return str[startp, endp - startp + 1]
  end
end
o = Class1.new
str = 'ABCDEFG'
puts o.substr(str, 1, 3)
puts o.substring(str, 0, 1)

モジュールをある特定のオブジェクトに包含することもできます。その場合は、extendを使います。次のサンプルでは、Class1のインスタンス(o)にModule1をextendしているので、Module1のメソッド substr が o のメソッドとして使えます。

(例) extendの使用例

module Module1
  def substr(str, start, length)
    return str[start, length]
  end
end
class Class1
  def substring(str, startp, endp)
    return str[startp, endp - startp + 1]
  end
end
o = Class1.new
o.extend Module1  # <==
puts o.substr('ABCDEF', 1, 3)

例外処理

例外処理はC#ではtry..catch..finally構文を使います。Rubyではbegin..rescue..ensure構文を使います。beginがtry、rescueがcatch、ensure が finally に対応します。

@button1.click do |sender, e|
  begin
    ....
    MessageBox.Show("Normal Termination.", "Result")
  rescue => e
    MessageBox.Show("Fatal Error. " + e.Message, "Result")
  ensure
  end
      

 

 続く ..

 

 開設 2014年12月   著作権 2014-2015 bonk.red  連絡先: こちらからメッセージを送ってください。 (お仕事も大募集)

 このページの先頭へ..