.NET 互操作

入门 IronRuby 和 RSpec,第 1 部分

Ben Hall

本文基于 IronRuby 的预发布版本。如更改,恕所有信息。

本文讨论:

  • 拼音、 和鸭子类型化
  • 拼音、 和 Microsoft.NET Framework
  • 使用 IronRuby 和 RSpec
本文涉及以下技术:
IronRuby

代码下载可从 MSDN 代码库
浏览代码联机

内容

在代码中定义要求和示例
拼音、 和鸭子类型化
拼写和 MetaProgramming
Ruby 和.NET Framework
拼音、 和 CLR
内部 IronRuby
测试与 IronRuby 一个 C# 应用程序
向前移动

"这不是我们要求 !" 我确信大多数开发人员必须提供最新版本后不久听到来自客户的此 cry。客户可能由于各种原因叫嚷在较差的开发人员也许要求不正确理解或系统的部分只是做不工作。

因为客户通常是与他们自己的要求不清楚,他们将选择对试图定义所有系统可能需要执行的 100 页技术文档的安全。同时,与未记录旧代码,尝试了解如何应用程序为了工作而不会破坏任何实现新的要求时,开发人员 struggles。

将更改时间。软件开发的新方法旨在解决帮助您满足而不会故障导致进程中的客户要求在第一次尝试在这些问题。这些方法利用语言如拼音、,使您可以轻松地读取和易于维护的代码创建更短的开发迭代。

此文章中, 我将向您介绍 Ruby 和 IronRuby 并演示的拼写与 Microsoft 基于.NET Framework 的代码进行互操作的一些基础知识。我还介绍了如何使用如 RSpec 框架生成的方式对象为了行为,示例提供文档和系统生成正确的验证。这将设置为将来的项目中我将介绍验收测试详细信息,并演示 IronRuby 创建验收测试阶段。

在代码中定义要求和示例

为了帮助编写的示例,并定义要求需要一个框架。有许多不同的方法编写自动化的验收测试或可执行文件的规范。其他人使用调整和适用性的框架时,有些人成功,使用标准 xUnit 测试框架。我已发现最好的方法是使用行为驱动开发 (BDD)。Dan North 设计了一个BDD Framework 调用 JBehave作为一种定义方案,介绍一种方式可以将传递到整个团队无论技术的功能的应用程序的行为。

JBehave 是的问题 North 面临用测试驱动开发 (TDD) 和 Java 语言中已实现的结果。以后,North 创建由于已集成到 RSpec 的拼音、 流行框架的 RBehave。RSpec 适合 BDD 两种不同方法: 根据文章和方案描述应用程序的行为的 Dan North 方法和Dave Astels 方法的更多集中在对象级别创建的示例。

C# 也有一些 BDD 框架 NSpec 和 NBehave。在 C# 编写测试,主要问题是满足测试的目的通常由于而隐藏您有其他结构元素和元数据 (如大括号公钥和私钥的事实。总体,我不认为通过 C# 的提供程序是,和 NSpec / NBehave 可以匹配是通过 IronRuby 和 RSpec 可用。以前,这将已主要问题的 C# 开发,您可能不具有使用拼音、 基于 RSpec 测试 C# 应用程序。与 IronRuby,这不是一个问题。

时仍在早期开发,IronRuby 利用动态语言运行时 (DLR) 以创建在 CLR 之上拼写的语言的实现。与 IronRuby,您可以使用现有的拼音应用程序和一起与.NET Framework 和.NET 兼容语言的框架。结果是可以使用拼写的语言和 RSpec 测试 C# 应用程序 !

一种语言拼音、 是简洁允许您编写较少的代码和 Express 它以更自然方式使您的代码更易于维护。是例如从文件读取的文本的所有行和写入这些出控制台,您将编写此:

File.readlines('AboutMicrosoft.txt').map {|line| puts line}

该代码打开文件 AboutMicrosoft.txt,并显示所有行,将每行传递到包含与一个参数,然后写入控制台在行在块。 在拼音、,块的大括号之间的语句集合并且为类似于调用 C# 中,使用 yield 语句将控制返回给调用方法的方法。

其自然语言方法是拼音、 测试时使用极佳,原因之一。 在测试,或方案在这种情况下是得更容易阅读。

拼音、 和鸭子类型化

之一为何拼写和动态语言是易于阅读的原因是由于如何处理输入。 而不是开发人员在中断拼音代码定义一种类型变量的类型推断。 所使用的语言仍强类型的但动态确定变量的类型。

使用 C# 接口允许 decoupling 对象的同时还定义用于实现一个约定。 与拼音、,没有必要为合同和接口。 相反,如果对象具有要调用该方法的实现,然后它的调用。 如果它所不则会返回错误。 在这种情况下,由它的实现不与代码的其他部分的关系定义对象的合同。

为了说明这,我创建接受的值的类型将推断在运行时的方法。 它然后将输出 Hello 加上值:

   def SayHello(val)
     puts "Hello #{val}"
   end

因处理类型的方式,可以而不更改任何代码重复使用相同的方法为字符串和整数:

   SayHello("Test") => "Hello Test"
   SayHello(5) => "Hello 5"

我可能有也具有调用该方法无括号,这些可选在拼音、 以及可以使语法得更具可读性:

   SayHello "Test" => "Hello Test"

这可以实现 C# 中使用对象,但让我们看看这如何使用更复杂的对象。 我定义一个新方法输出 GetName 调用的结果。 只要参数 n 的值实现方法调用 GetName,将工作代码:

def outputName(n)
  puts n.GetName()
end 

下面是两个不相关的类:

class Person
  attr_accessor :name
  def GetName()
    @name
  end
end
class Product
  def GetName()
    "The product with no name"
  end
end

用户有一个访问器,允许名称变量将设置而产品返回硬编码值。 在拼音、,没有需要写入该返回的语句方法的代码的最后一行的最后结果由默认值返回。

如果您在调用方法 outputName 将 GetName 调用方法,演示如何 Ruby 的键入可以增强代码可重用性由于我们不固定为一种类型:

outputName(Product.new) => "The product with no name"
$x = Person.new
$x.name = "Ben Hall"
outputName($x) => "Ben Hall"

如果在调用使用一个参数,不实现 GetName 方法,一个 NoMethodError 将会引发:

outputName("MyName") => :1:in 'outputName': \
  undefined method 'GetName' \
  for MyName:String (NoMethodError)

这一概念与某些人时, 它可以是非常有用 ; 它可以改进的 testability 和应用程序设计尤其是当测试我将在下一节中讨论 C# 应用程序。

拼写和 MetaProgramming

类似于其他动态语言,拼音、 embraces 的概念元编程。 这允许您扩展任何类或对象运行时使您可以定义方法和行为运行时让您能够开发 self-modifying 应用程序。 这是非常有用,尤其是在单元测试,之类的动态语言中它允许您自定义对象和您自己的要求的方法的行为。

以类似的方式可以扩展以提供您自己功能,内置的拼音类非常像在 C# 3.0 中的扩展方法。 使用 C# 有方法可以创建的各种限制。 是例如他们必须是静态的和单独的类。 此所有损害可读性。 与拼音、,您只是创建一个正常方法的现有类上。 是例如整数是处理整数类。 整数有一系列的方法,但它没有方法是否甚至是数。

若要创建这样的方法,您只需创建一个新类具有相同的名称 (整数),定义新的方法。 该方法的结尾处的问号表示一个 Boolean 类型值返回使易于阅读的目的:

class Integer
   def even?()
       self.abs % 2 == 0
   end
end
puts 2.even? => true
puts 1.even? => false

Ruby 和.NET Framework

代替有关是否使用静态或动态语言旧的争论,IronRuby 可以为作业使用正确的语言。 如果有意义更多使用 C#,您可以使用 C#。 如果您需要一个更具动态方法,可以轻松地使用 IronRuby,利用与.NET 的互操作性和拼写的语言的动态特征。 我预计使用多种不同语言和等不是针对主应用程序和用于测试的拼音、 C# 的技术的人。

DLR 提供了启用.NET 互操作。 与此位置,您可以利用用户界面技术 (如 Windows 窗体、 Windows Presentation Foundation (WPF) 和 Silverlight 在拼音、 写入应用程序代码时。

利用 WPF 从 IronRuby 很容易。 下面的代码执行时, 您可以从 IronRuby 创建一个功能完善的 WPF 窗口。 您仍然必须引用 mscorlib 和两个 WPF 程序集提供了在 N 一样使用 C# 使用在需要语句:

require 'mscorlib'
require 'PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
require 'PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

现在可以创建和与 WPF 对象的交互。 首先,创建为您要使用的所有对象的别名。 这会使该代码清洗器,不需要访问对象通过命名空间:

Window = System::Windows::Window
Application = System::Windows::Application
Button = System::Windows::Controls::Button

接下来,创建 WPF 窗口,并为其指定标题:

win = Window.new
win.title = 'IronRuby and WPF Interop'

创建按钮以相同的方式:

mainButton = Button.new
mainButton.content = 'I'm a WPF button — press me'

在这两种情况我使用别名来访问该对象的完整名称。 单击该按钮是,我想向用户显示一个 MessageBox。 像在 C#,您可以订阅事件和提供一个调用 Click 事件时调用的块:

mainButton.click do |sender, args|
  System::Windows::MessageBox.Show("Created using IronRuby!")
end

最后,设置将要按钮、 创建新的应用程序对象和启动窗口窗口的内容:

win.content = mainButton
my_app = Application.new
my_app.run win

fig01.gif

图 1 使用 IronRuby 创建 WPF 应用程序

到目前为止将完全交互式的 WPF 窗口显示与正确有线设置,如 图 1 所示的单击事件。 我使用.NET Framework 交互我将交互拼音库方式相同。 通过 John Lam,团队设置出在核心原则之一是保持 True 为拼写的语言。 这是采用由当前拼写开发,那些不希望更改他们仅仅因为要转向 IronRuby 创建拼写的应用程序的方式的一个重要原则。 而是它们可以访问所有丰富的.NET 代码相同的方式。

拼音、 和 CLR

下面是另一个示例。 如果试图访问 IEnumerable 中的 AddRange 在 C# 代码如下: 所

ArrayList list = new ArrayList();
list.AddRange(new [] { 1,2,3,4 });

不过,使用 Ruby,可接受的约定,在方法名称来将分隔以提高可读性的下划线的词。 创建要遵循此约定单独的库对其是,太耗时以及易于出错,和它不支持其他第三方开发。

相反的 CLR 对象,IronRuby 将转换到 CLR 的等效方法名称的拼音方法调用:

   $list = ArrayList.new
   $list.add_range([1,2,3,4])

此处我正在访问以下是包含由一个下划线字符分隔的词语的小写的 Ruby 的方法 AddRange 方法。 如果您更喜欢您可以保留与 CLR 的命名约定因为方法名称仍然存在从拼音、:

$list.AddRange([1,2,3,4])

同时工作相同 ; 只是个人首选使用。

如我提到过拼音、 运行时推断出的对象的该类型,并且这是相同是处理 C# 对象时。 考虑一系列的 C# 方法返回不同的对象类型,同一对象将被返回时, 方法签名返回界面或具体的类型。 我的示例中,我有定义一个 HelloWorld 方法的接口:

public interface IHello {
  string HelloWorld();    
}

我创建了一个 Hello4Times 类 Hello3Times,从接口继承,但实现了三种额外的 Hello­World 方法所继承的。 类中我将定义一个称为 HelloMethodOn4Times 调用基实现的新方法:

public class Hello4Times : Hello3Times {
  public string HelloMethodOn4Times () {
    return base.HelloWorld();
  }
}

我然后定义一个静态类和方法,将返回 Hello4Times 类的新实例,但其返回到调用代码作为接口。 这意味着调用的代码应只知道 HelloWorld,不将任何其他方法定义:

public static class HelloWorld {
  public static IHello ReturnHello4TimesAsInterface() {
    return new Hello4Times();
  }

在我的拼音代码中,我有两个方法调用。 第一个调用将是定义接口的方法您会希望工作时不出现问题。 但是,第二次调用是具体类该方法。 IronRuby 已确定的返回的对象类型,并可以分派方法调用:

puts InteropSample::HelloWorld.ReturnHello4TimesAsInterface.HelloWorld
puts interopSample::HelloWorld.ReturnHello4TimesAsInterface.HelloMethodOn4Times

所有这些发生而过不必担心如何将对象转换为正确的类型调用方法。

按照此主题,您可以像可以使用拼音对象扩展.NET 对象,以完全相同的方式。 显示一个 MessageBox 时, 我不想保留定义的图标和按钮来使用。 相反,我只想提供消息。

也许您不要在喜欢内置功能,并希望扩展实际的 MessageBox 类,用于进行无缝交互。 与拼音、,这是简单。 您定义新的类,与 WPF 中内置的 MessageBox 相同的。 然后只需调用 Show 方法使用不同的默认值类上创建的新方法:

class System::Windows::MessageBox
  def self.ShowMessage(msg)
    System::Windows::MessageBox.Show(msg, msg, \
      System::Windows::MessageBoxButton.OK, \
      System::Windows::MessageBoxImage.Stop)
  end
end

在执行这段代码后

System::Windows::MessageBox.ShowMessage( \
  "I'm going to show you a message") 

您可以调用 ShowMessage 方法,在消息框中显示结果 图 2 .

fig02.gif

图 2 显示从 Ruby 的自定义 MessageBox

内部 IronRuby

互操作可能是什么? 答案是 DLR。 在较高的级别当您执行使用 IronRuby 的拼音代码大量工作将在后台。 首先,您编写的代码是标记,并分析由 IronRuby 引擎。 分析的代码然后转换为 DLR 的抽象语法树 (AST)。 这是一个标准化的 AST,如 IronPython 的所有语言实现都需要向 DLR 以执行代码的。

一旦 DLR 拥有将 AST,它将中间语言 (IL) 转换为树。 所有的.NET 代码下编译到 CLR 中提供一个泛型的语言的 IL。 这是 IronRuby 可以如何使用.NET Framework 互操作,作为 IL 说明在后台执行所有代码。 DLR 完成转换后,它传递给执行 CLR 的 IL,并且结果返回到 IronRuby。

在此过程有是以提高性能和如缓存的可靠性的其他步骤。 一个更深入的解释,我建议阅读 Bill Chiles CLR 列" Iron­Python 和动态语言运行库"2007 年 10 月发布的 MSDN 杂志 》 .

单独的程序集内有是一个托管 API,可以对自己的应用程序中嵌入 IronRuby 使您可以从 C# 或用户来执行其自己的代码执行拼写的代码。

更多有关 IronRuby 实现下载从整个源代码 RubyForge. IronRuby 在 C# 中实现的开源项目并且为一个动态语言实现的极好示例。 IronPython 是可用,因为在 CodePlex,和其托管一个开源项目包含调用 ToyScript 要介绍到 DLR 的工作原理的示例语言。

若要确保与核心拼音平台的连续的兼容,IronRuby 团队使用 RubySpecs。 这是示例基于拼写的语言应如何实现一个共享的组。 RubySpecs 的目的是确保包括 Matz 的拼音解释器 (MRI) 的不同实现,JRuby、 MacRuby,和 IronRuby 具有相同的行为。 RubySpecs 使用语法兼容版本的名为 MSpec RSpec。 这些被视为验收测试 IronRuby 实现的。

测试与 IronRuby 一个 C# 应用程序

现在很多年,意识和 TDD 的已增加作为一种开发方面的设计和可维护性一起途中减少缺陷的高质量代码所导致的软件。 与 IronRuby,我可以使用 RSpec 规范框架和 Runner 提供如何我的 C# 对象工作,以下 BDD 方法,而不是 TDD 的示例。

验收测试在应用程序级别的多对齐方案我将在以后的文章中介绍的 Framework 时, 的指定有关代码编写自己的规范的开发人员更对齐 Framework 它们是几乎实现与预期的行为。 指定框架基于提供描述在对象级别行为的示例。 这些示例可以运行验证开发人员的要求同时提供有关如何对象预期的行为的文档仍然工作系统的实现。

这是与如 Nunit 进行测试和 MbUnit 单元测试框架的重要区别。 这两个使用测试属性以指示一种方法是系统的测试。 RSpec 采用其他方法。 RSpec 显示每个方法为如何代码是要使用的一个示例。 细微区别时它将更改方式编写包括您使用,您组织在的方法和如何轻松地概念可理解为 TDD 的比较方式的术语的这些示例。 使用 BDD 和 RSpec,IronRuby 关闭集成和在.NET Framework 可以启动使用 IronRuby 测试 C# 应用程序。 示例,方面的经典的 RSpec 示例是球游戏。

首先,您需要访问球游戏的实现是 C# 程序集:

require File.dirname(__FILE__) + \
  '/InteropSamples/Bowling/Bowling/bin/Debug/bowling.dll'

然后需要访问 RSpec:

require 'rubygems'
require 'spec'

现在可以开始编写的示例。 这是示例显示如何 bowling 实现应该工作。 RSpec 具有域特定语言 (DSL) 则必须按照示例要执行的。 第一部分在 DSL 的是在介绍块。 此处只是声明您要在"描述"结合可选说明该对象。 在这种情况下我将定义球对象将实现 C# 中:

describe Bowling, " defines the bowling game" do

若要提高可读性,将在执行任何安装程序在 before 块:

  before(:each) do  
    @bowling = Bowling.new 
  End

现在,我是在位置与对象交互、 创建示例和验证它正常工作正常。 我使用"它"块,提供说明示例而它演示的上下文字符串。 然后,我编写与系统交互和验证发生了正确的操作的代码的部分:

  it "should score 0 for a gutter game" do
    20.times { @bowling.hit(0) }
    @bowling.score.should == 0
  end
end

C# 实现只是如下所示:

public class Bowling {
  public int Score { get; set; }
  public void Hit(int pins)
    { Score += pins; }
}

最后,执行此验证球将按预期方式与 RSpec 测试 C# 对象有效:

>ir bowling_spec.rb
.
Finished in 1.0458315 seconds
1 example, 0 failures

如果我想更详细的报表,我可以选择为 specdoc 格式。 此输出一起使用所有示例,说明是否它们已传递或不在对象说明:

>ir bowling_spec.rb --format specdoc
Bowling defines the bowling game
- should score 0 for a gutter game
Finished in 1.43728 seconds
1 example, 0 failures

在编写时,IronRuby 团队不定期传送二进制文件。 团队有说它正在等待直到满意实施、 兼容性和释放正式的二进制文件前的性能。 但是,因为源代码可自由地用的您可以下载代码并构建您自己。

要下载源代码,需要如有 git 源控件客户 msysgit安装。 在 IronRuby 源代码管理联机才可用。 如果您希望更多信息,则建议您访问在 IronRuby 项目网站 或我的博客张贴内容" 从 GitHub 下载 IronRuby." 源代码您下载后您可以编译该程序集与使用 IronRuby.sln 解决方案文件的 Visual Studio 或者,如果 MRI 安装然后您可以使用命令:

rake compile

后 IronRuby 编译必须下载 RSpec,获得额外的功能 (如) 之类的各种库。 拼音、 有一个概念 RubyGems 在宝石的包的您可以下载获得功能和附加依赖项。 要下载 RSpec,请在命令提示符处键入以下:

gem install rspec

您将现在能够访问从 RSpec 库,在拼音代码中。 但是,在编写时,RSpec NTE IronRuby 由于到一个或两个错误。 希望时此文章将发布 RSpec 应要与处理 IronRuby 而。 要了解 RSpec 支持的状态,请参阅在 RSpec Web 站点IronRuby 邮寄列表.

如果 Bug 未被修复,我做一个 与一起与 RSpec 库就地修复的 Bug 的二进制文件. (注意: 团队已修复该问题后,不使用此版本)

一旦您有正确的二进制文件,ir.exe 将是 IronRuby 解释器,可以执行您的代码。 如果只是启动应用程序从命令行则将输入交互控制台。 在拼音、,学习和调试,但也运行短信指令来解决每天的问题的极好在行的行基础上执行代码。 如果提供文件名作为参数,然后将该文件执行与结果输出到控制台。

向前移动

在我的下一文章中,我将引入验收测试以及它如何提高客户和开发人员之间的通信的概念。 我将演示如何验收测试才能自动使用 IronRuby 和 RSpec 验证.NET 应用程序,并创建为系统的可执行文件规范。

Ben Hall 是 C# 开发 / 测试人员与 for Software Development 的强热情,和喜欢编写代码。 本工作在英国的红色 Gate Software 为测试工程师和受浏览包括手动和自动测试侧重于测试的应用程序的不同类型的最佳方式的测试软件的不同方式。 Ben 是 C# MVP,并维护在博客 Blog.BenHall.Me.uk.