bewildr 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,107 +1,118 @@
1
1
  =bewildr
2
- Test WPF apps in (iron) ruby!
2
+ Test WPF UI apps with (iron) ruby!
3
3
 
4
4
  Written by Nat Ritmeyer (http://www.natontesting.com)
5
5
 
6
6
  ==Intro
7
- <b>This is pre-alpha software - it has a way to go before being complete...</b>
8
-
9
7
  Documentation is on the way; until then, take a look at the tests or read the API overview below.
10
8
 
11
9
  ==Getting started
12
- ===Installation
10
+ ===Dependencies
11
+ 1. Install .net 3 and 4 (http://www.microsoft.com/downloads/details.aspx?FamilyID=10cc340b-f857-4a14-83f5-25634c3bf043&displaylang=en & http://msdn.microsoft.com/en-us/netframework/aa569263.aspx)
12
+ 2. Install the latest ironruby (http://www.ironruby.net/), and for your own sanity install it in c:\\\\ironruby instead of the default location.
13
+ 3. You'll need at least rubygems version 1.3.6:
14
+ gem update --system
13
15
 
14
- Install the latest ironruby (http://www.ironruby.net/), and for your own sanity install it in c:\\\\ironruby instead of the default location.
15
-
16
- <tt>
17
- gem install bewildr
18
- </tt>
16
+ ===Installation
19
17
 
20
- You'll need at least rubygems version 1.3.6 (gem update --system)
18
+ gem install bewildr --no-rdoc --no-ri
21
19
 
22
- ===API Overview
20
+ To use bewildr:
23
21
 
24
- <b>Start an app</b>
22
+ require 'bewildr'
25
23
 
26
- <tt>@app = Bewildr::Application.start('notepad')</tt>
24
+ ==API Overview
25
+ ===Application Management
26
+ Start an app
27
27
 
28
- <tt>@app = Bewildr::Application.start('c:/windows/notepad.exe')</tt>
28
+ @app = Bewildr::Application.start('notepad')
29
+ @app = Bewildr::Application.start('c:/windows/notepad.exe')
29
30
 
30
- <b>Start an app and wait for a particular window:</b>
31
+ Start an app and wait for a particular window:
31
32
 
32
- <tt>@app, @window = Bewildr::Application.start_app_and_wait_for_window('notepad', 'Untitled - Notepad')</tt>
33
+ @app, @window = Bewildr::Application.start_app_and_wait_for_window('notepad', 'Untitled - Notepad')
33
34
 
34
35
  or (taking a regex for the window title instead of a string - tests become more robust):
35
36
 
36
- <tt>@app, @window = Bewildr::Application.start_app_and_wait_for_window('c:/windows/notepad.exe', /.* - Notepad/)</tt>
37
-
38
- <b>kill an app</b>
39
-
40
-
41
- <tt>@app.kill</tt>
37
+ @app, @window = Bewildr::Application.start_app_and_wait_for_window('c:/windows/notepad.exe', /.* - Notepad/)
42
38
 
43
- <tt>@app.running? == false</tt>
39
+ Kill an app
44
40
 
45
- <tt>@app.should_not be_running</tt>
41
+ @app.kill
42
+ @app.running? == false
43
+ @app.should_not be_running
46
44
 
47
- <b>Get application windows:</b>
45
+ ===Window Management
46
+ Get application windows:
48
47
 
49
48
  All windows belonging to an app:
50
49
 
51
- <tt>@all_windows_for_my_app = @app.get_windows</tt>
50
+ @all_windows_for_my_app = @app.windows
52
51
 
53
52
  Window with a particular name:
54
53
 
55
- <tt>@main_window = @app.get_window('My App 1.0')</tt>
54
+ @main_window = @app.window('My App 1.0')
56
55
 
57
56
  Window with a particular name (find window using regex instead of string):
58
57
 
59
- <tt>@main_window = @app.get_window(/My App .*/)</tt>
58
+ @main_window = @app.window(/My App .*/)
60
59
 
61
- <b>Find an element by its automation id:</b>
60
+ ===Basic Element Interaction
62
61
 
63
- <tt>my_button = @window.get(:id => 'my_button')</tt>
62
+ Find an element by its automation id:
64
63
 
65
- <b>Find an element by its type:</b>
64
+ my_button = @window.get(:id => 'my_button')
66
65
 
67
- <tt>@all_buttons = @window.get(:type => :button)</tt>
66
+ Find an element by its type:
68
67
 
69
- <b>Find an element by its name:</b>
68
+ @all_buttons = @window.get(:type => :button)
70
69
 
71
- <tt>my_button = @window.get(:name => 'Click Here')</tt>
70
+ Find an element by its name:
72
71
 
73
- <b>Find an element by a combination of criteria:</b>
72
+ my_button = @window.get(:name => 'Click Here')
74
73
 
75
- <tt>@main_window.get(:type => :hyperlink, :name => "Link Text")</tt>
74
+ Find an element by a combination of criteria:
76
75
 
77
- <b>Click a button:</b>
76
+ @main_window.get(:type => :hyperlink, :name => "Link Text")
78
77
 
79
- <tt>@window.get(:id => 'my_button').click</tt>
78
+ Click a button:
80
79
 
81
- <b>Check for existence/enabled state of an element:</b>
80
+ @window.get(:id => 'my_button').click
82
81
 
83
- <tt>@window.get(:id => 'some_element').exists?</tt>
82
+ ===Element State
84
83
 
85
- <tt>@window.get(:id => 'some_element').enabled?</tt>
84
+ Check for existence/enabled state of an element:
85
+
86
+ @window.get(:id => 'some_element').exists?
87
+ @window.get(:id => 'some_element').enabled?
86
88
 
87
89
  ...which allows for some nice idiomatic test code if you're using rspec:
88
90
 
89
- <tt>@window.get(:id => 'some_element').should_not exist</tt>
91
+ @window.get(:id => 'some_element').should_not exist
92
+ @window.get(:id => 'some_element').should be_enabled
93
+
94
+ Wait for an element to exist:
95
+
96
+ @window.wait_for_existence_of(:id => "an_object")
97
+
98
+ Wait for an element to disappear:
99
+
100
+ @window.wait_for_non_existence_of(:id => "an_object")
101
+
102
+ The wait_for_existence_of method can be called recursively:
103
+
104
+ @window.wait_for_existence_of(:id => "an_object").wait_for_existence_of(:id => "child_object")
90
105
 
91
- <tt>@window.get(:id => 'some_element').should be_enabled</tt>
106
+ The line above will result in waiting for 'an_object', and once it has appeared it'll wait for an
107
+ object below it in the object hierarchy called 'child_object'.
92
108
 
93
109
  ==Background story
94
- I've recently been testing a WPF app using ironruby and the White automation library
95
- (see http://www.natontesting.com/2010/02/17/how-to-test-a-wpf-app-using-ironruby-and-white/
96
- for an example of my adventures). White proved to be buggy, painful and worst of all, slow.
97
- The whole time I was writing the framework and the tests, I wanted a replacement for white -
98
- something written in ruby, something that talked directly to MS Automation, something that
99
- had a simple architecture (trying to figure out what's going in in white is not trivial) and
100
- something that could be used to write idiomatic tests (using rspec matchers).
101
-
102
- Thus, Bewildr. "Scratch your own itch", and all that.
103
-
104
- Why 'bewildr'? Quite simply, I have been bewildrd for the whole journey. Bewildrd by white,
105
- bewildrd by Microsoft's automation architecture (which turns out, in fact, to be very well
106
- thought out - it just required a mind-shift, that's all) and bewildrd as a result of the
107
- recent late nights writing bewildr.
110
+ I've recently being testing a WPF app. I wrote some classes to wrap the White automation library
111
+ (http://white.codeplex.com/) using IronRuby to allow the WPF app tests to be written in ruby - the
112
+ same language as the tests for the other systems. Due to some performance issues and a number of
113
+ bugs, I ended up rewriting large chunks of the functionality of white by directly talking to the MS
114
+ Automation API (http://msdn.microsoft.com/en-us/library/ms747327(v=VS.100).aspx). After a while it
115
+ occured to me... "why not write a library from scratch that tests WPF apps, that's fast and allows
116
+ for idiomatic tests due to a clean API?"
117
+
118
+ Enter 'Bewildr'.
data/Rakefile CHANGED
@@ -10,10 +10,10 @@ require 'cucumber/rake/task'
10
10
 
11
11
  spec = Gem::Specification.new do |s|
12
12
  s.name = 'bewildr'
13
- s.version = '0.1.1'
13
+ s.version = '0.1.2'
14
14
  s.has_rdoc = true
15
15
  s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
16
- s.summary = 'Test your WPF apps with (iron) ruby!'
16
+ s.summary = 'Test WPF UI apps with (iron) ruby!'
17
17
  s.description = s.summary
18
18
  s.author = 'Nat Ritmeyer'
19
19
  s.email = 'nat@natontesting.com'
@@ -48,5 +48,5 @@ Spec::Rake::SpecTask.new do |t|
48
48
  end
49
49
 
50
50
  Cucumber::Rake::Task.new(:features) do |t|
51
- t.cucumber_opts = "features --format pretty --no-color"
51
+ t.cucumber_opts = "features --format pretty --no-color -q"
52
52
  end
@@ -10,6 +10,7 @@ raise LoadError, "Bewildr only works under IronRuby" unless RUBY_ENGINE == "iron
10
10
  load_assembly 'UIAutomationClient, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
11
11
  load_assembly 'UIAutomationTypes, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
12
12
  load_assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
13
+ load_assembly 'System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
13
14
 
14
15
  #require BewildrClickr - stopgap until the ffi gem works under ironruby
15
16
  require File.join(File.expand_path(File.dirname(__FILE__)), "bewildr", "ext", "BewildrClickr.dll")
@@ -37,6 +38,7 @@ require 'bewildr/control_patterns/selection_item_pattern'
37
38
  require 'bewildr/control_patterns/range_value_pattern'
38
39
  require 'bewildr/control_patterns/grid_pattern'
39
40
  require 'bewildr/control_patterns/table_pattern'
41
+ require 'bewildr/control_patterns/text_pattern'
40
42
 
41
43
  require 'bewildr/control_type_additions/text_additions'
42
44
  require 'bewildr/control_type_additions/combo_box_additions'
@@ -47,4 +49,5 @@ require 'bewildr/control_type_additions/tab_additions'
47
49
  require 'bewildr/control_type_additions/list_additions'
48
50
  require 'bewildr/control_type_additions/tree_additions'
49
51
  require 'bewildr/control_type_additions/tree_item_additions'
50
- require 'bewildr/control_type_additions/data_grid_additions'
52
+ require 'bewildr/control_type_additions/data_grid_additions'
53
+ require 'bewildr/control_type_additions/document_additions'
@@ -10,9 +10,9 @@ module Bewildr
10
10
  private :initialize
11
11
 
12
12
  def kill
13
- @proc.kill
13
+ `taskkill /f /t /pid #{@proc_id}`
14
14
  Timeout::timeout(5) do
15
- sleep 0.1 until @proc.has_exited
15
+ sleep 0.1 while running?
16
16
  end
17
17
  end
18
18
 
@@ -26,41 +26,37 @@ module Bewildr
26
26
  end
27
27
  end
28
28
 
29
- def get_windows
29
+ def windows
30
30
  Bewildr::Windows.windows_by_process_id(@proc_id)
31
31
  end
32
32
 
33
- def get_window_by_name(input)
33
+ def window_by_name(input)
34
34
  case input
35
- when String then return get_windows.select{|window| window.name.strip == input.strip}.first
36
- when Regexp then return get_windows.select{|window| input.match(window.name.strip).nil? == false}.first
35
+ when String then return windows.select{|window| window.name.strip == input.strip}.first
36
+ when Regexp then return windows.select{|window| input.match(window.name.strip).nil? == false}.first
37
37
  else
38
38
  raise ArgumentError, "input not a string or regexp but a #{input.class}"
39
39
  end
40
40
  end
41
- alias :get_window :get_window_by_name
41
+ alias :window :window_by_name
42
42
 
43
43
  def wait_for_window(input, wait_time = 30)
44
44
  begin
45
- Timeout::timeout(wait_time) do
46
- begin
47
- my_window = get_window(input)
48
- raise if my_window.nil?
49
- return my_window
50
- rescue
51
- sleep 0.2
52
- retry
45
+ Timeout::timeout(wait_time) do
46
+ begin
47
+ my_window = window(input)
48
+ raise if my_window.nil?
49
+ return my_window
50
+ rescue
51
+ sleep 0.2
52
+ retry
53
+ end
53
54
  end
54
- end
55
55
  rescue Timeout::Error
56
56
  raise ElementDoesntExist
57
57
  end
58
58
  end
59
59
 
60
- def window_count
61
- get_windows.size
62
- end
63
-
64
60
  #takes name or full path of exe to start
65
61
  def self.start(process_name)
66
62
  Bewildr::Application.new(System::Diagnostics::Process.start(process_name))
@@ -78,6 +74,18 @@ module Bewildr
78
74
  Bewildr::Application.new(process)
79
75
  end
80
76
 
77
+ def self.attach_or_launch(path_to_exe)
78
+ #if app is already open attach to it
79
+ potential_process_name = File.basename(path_to_exe, ".exe")
80
+ if Bewildr::Application.processes_with_name(potential_process_name).size > 0
81
+ #app is running, attach to it
82
+ Bewildr::Application.attach_to_process_name(potential_process_name)
83
+ else
84
+ #app is not running, start a new instance
85
+ Bewildr::Application.start(path_to_exe)
86
+ end
87
+ end
88
+
81
89
  def self.start_app_and_wait_for_window(path, window_name)
82
90
  app = Bewildr::Application.start(path)
83
91
  window = app.wait_for_window(window_name)
@@ -85,11 +93,19 @@ module Bewildr
85
93
  end
86
94
 
87
95
  def self.kill_all_processes_with_name(input)
88
- System::Diagnostics::Process.get_processes_by_name(input).each {|p| p.kill}
96
+ System::Diagnostics::Process.get_processes_by_name(input).each do |p|
97
+ p.kill
98
+ p.wait_for_exit
99
+ end
89
100
  end
90
101
 
91
102
  def self.processes_with_name(input)
92
103
  System::Diagnostics::Process.get_processes_by_name(input).collect {|p| Bewildr::Application.attach_to_process(p) }
93
104
  end
105
+
106
+ def self.wait_for_process_with_name(input)
107
+ Timeout.timeout(30) {sleep 0.1 until System::Diagnostics::Process.get_processes_by_name(input).size > 0}
108
+ self.attach_to_process_name(input)
109
+ end
94
110
  end
95
111
  end
@@ -7,6 +7,10 @@ module Bewildr
7
7
  @automation_element.get_current_pattern(System::Windows::Automation::RangeValuePattern.pattern).current.value
8
8
  end
9
9
 
10
+ def value=(input)
11
+ @automation_element.get_current_pattern(System::Windows::Automation::RangeValuePattern.pattern).set_value(input.to_f)
12
+ end
13
+
10
14
  def maximum
11
15
  @automation_element.get_current_pattern(System::Windows::Automation::RangeValuePattern.pattern).current.maximum
12
16
  end
@@ -18,10 +18,7 @@ module Bewildr
18
18
  end
19
19
 
20
20
  def selected
21
- case can_select_multiple?
22
- when true then get_selection
23
- when false then get_selection.first
24
- end
21
+ can_select_multiple? ? get_selection : get_selection.first
25
22
  end
26
23
  end
27
24
  end
@@ -0,0 +1,15 @@
1
+ #Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.s
2
+
3
+ module Bewildr
4
+ module ControlPatterns
5
+ module TextPattern
6
+ def select_all
7
+ @automation_element.get_current_pattern(System::Windows::Automation::TextPattern.pattern).document_range.select
8
+ end
9
+
10
+ def get_text
11
+ @automation_element.get_current_pattern(System::Windows::Automation::TextPattern.pattern).document_range.get_text(-1)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -24,6 +24,10 @@ module Bewildr
24
24
  state == :off
25
25
  end
26
26
 
27
+ def indeterminate?
28
+ state == :indeterminate
29
+ end
30
+
27
31
  def checked_state
28
32
  state
29
33
  end
@@ -0,0 +1,24 @@
1
+ #Copyright (c) 2010, Nathaniel Ritmeyer. All rights reserved.
2
+
3
+ module Bewildr
4
+ module ControlTypeAdditions
5
+ module DocumentAdditions
6
+ def self.extended(base)
7
+ base.extend Bewildr::ControlPatterns::TextPattern
8
+
9
+ base.instance_eval do
10
+ def text
11
+ get_text
12
+ end
13
+
14
+ def text=(input)
15
+ focus
16
+ select_all
17
+ System::Windows::Forms::SendKeys.send_wait("{DEL}")
18
+ System::Windows::Forms::SendKeys.send_wait(input)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -11,6 +11,45 @@ module Bewildr
11
11
  selectable_elements = get(:type => :list_item, :scope => :children)
12
12
  selectable_elements.find {|selectable_element| selectable_element.name == input}.select
13
13
  end
14
+
15
+ def items
16
+ my_list_items = list_items
17
+ return nil if my_list_items.nil?
18
+ my_list_items.collect {|item| item.name}
19
+ end
20
+
21
+ def list_items
22
+ bewildr_list_items = get(:type => :list_item, :scope => :children)
23
+ bewildr_list_items.nil? ? nil : bewildr_list_items
24
+ end
25
+
26
+ def count
27
+ my_items = items
28
+ my_items.nil? ? 0 : my_items.size
29
+ end
30
+
31
+ def select(input)
32
+ case input
33
+ when String then select_by_name(input)
34
+ when Integer then select_by_index(input)
35
+ else raise ArgumentError, "Select by name or by index"
36
+ end
37
+ end
38
+
39
+ def select_by_name(input)
40
+ my_item = list_items.find {|item| item.name == input}
41
+ raise NoSuchItemInListBox if my_item.nil?
42
+ my_item.select
43
+ end
44
+
45
+ def select_by_index(input)
46
+ raise "Index must be 0 or greater" if input < 0
47
+ my_item = list_items[input].select
48
+ end
49
+
50
+ def selected
51
+ get_selection.first.name
52
+ end
14
53
  end
15
54
  end
16
55
  end
@@ -12,6 +12,10 @@ module Bewildr
12
12
  def root_menu_items
13
13
  get(:type =>:menu_item, :scope => :children)
14
14
  end
15
+
16
+ def root_menu_item_names
17
+ root_menu_items.collect {|menu_item| menu_item.name}
18
+ end
15
19
 
16
20
  def select_menu(path)
17
21
  menu_item(path).click
@@ -8,9 +8,22 @@ module Bewildr
8
8
 
9
9
  base.instance_eval do
10
10
  def select(input)
11
- selectable_elements = get(:type => :tab_item, :scope => :children)
11
+ raise NoSuchTab unless tab_names.include?(input)
12
+ selectable_elements = tabs
12
13
  selectable_elements.find {|selectable_element| selectable_element.name == input}.select
13
14
  end
15
+
16
+ def tabs
17
+ get(:type => :tab_item, :scope => :children)
18
+ end
19
+
20
+ def tab_names
21
+ tabs.collect {|tab| tab.name}
22
+ end
23
+
24
+ def selected
25
+ tabs.find {|tab| tab.selected?}
26
+ end
14
27
  end
15
28
  end
16
29
  end
@@ -11,6 +11,18 @@ module Bewildr
11
11
  def child_nodes
12
12
  get(:type => :tree_item, :scope => :children)
13
13
  end
14
+
15
+ #horrible, but necessary - clickable point for tree items doesn't work like you think it would...
16
+ #I've added 7 to y and 22 to x... that's working for now... this is hardly the ideal solution...
17
+ #To see what's going on with the following code, take a look at a tree node under uispy - you'll
18
+ #understand - a picture paints a thousand words and all that.
19
+ def clickable_point
20
+ existence_check
21
+ ae_top_left_point = @automation_element.current.bounding_rectangle.top_left
22
+ ae_top_left_point.x += 22
23
+ ae_top_left_point.y += 7
24
+ ae_top_left_point
25
+ end
14
26
  end
15
27
  end
16
28
  end
@@ -65,6 +65,10 @@ module Bewildr
65
65
  end
66
66
  end
67
67
 
68
+ def focus
69
+ @automation_element.set_focus
70
+ end
71
+
68
72
  #:id => "id"
69
73
  #:name => "bob"
70
74
  #:type => :button
@@ -133,6 +137,7 @@ module Bewildr
133
137
  extend Bewildr::ControlTypeAdditions::DataGridAdditions
134
138
  when :data_item
135
139
  when :document
140
+ extend Bewildr::ControlTypeAdditions::DocumentAdditions
136
141
  when :edit
137
142
  extend Bewildr::ControlPatterns::ValuePattern
138
143
  when :group
@@ -158,6 +163,7 @@ module Bewildr
158
163
  when :scroll_bar
159
164
  when :seperator
160
165
  when :slider
166
+ extend Bewildr::ControlPatterns::RangeValuePattern
161
167
  when :spinner
162
168
  when :split_button
163
169
  when :status_bar
@@ -4,5 +4,7 @@ class ElementNotEnabled < StandardError; end
4
4
  class ElementDoesntExist < StandardError; end
5
5
  class PasswordFieldReadAttempt < StandardError; end
6
6
  class NoSuchItemInComboBox < StandardError; end
7
+ class NoSuchItemInListBox < StandardError; end
8
+ class NoSuchTab < StandardError; end
7
9
 
8
10
  class BewildrInternalError < StandardError; end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bewildr
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 31
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 1
8
- - 1
9
- version: 0.1.1
9
+ - 2
10
+ version: 0.1.2
10
11
  platform: ruby
11
12
  authors:
12
13
  - Nat Ritmeyer
@@ -14,11 +15,11 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-04-29 00:00:00 +01:00
18
+ date: 2010-06-07 00:00:00 +01:00
18
19
  default_executable:
19
20
  dependencies: []
20
21
 
21
- description: Test your WPF apps with (iron) ruby!
22
+ description: Test WPF UI apps with (iron) ruby!
22
23
  email: nat@natontesting.com
23
24
  executables: []
24
25
 
@@ -40,12 +41,14 @@ files:
40
41
  - lib/bewildr/control_patterns/selection_item_pattern.rb
41
42
  - lib/bewildr/control_patterns/selection_pattern.rb
42
43
  - lib/bewildr/control_patterns/table_pattern.rb
44
+ - lib/bewildr/control_patterns/text_pattern.rb
43
45
  - lib/bewildr/control_patterns/toggle_pattern.rb
44
46
  - lib/bewildr/control_patterns/value_pattern.rb
45
47
  - lib/bewildr/control_patterns/window_pattern.rb
46
48
  - lib/bewildr/control_type.rb
47
49
  - lib/bewildr/control_type_additions/combo_box_additions.rb
48
50
  - lib/bewildr/control_type_additions/data_grid_additions.rb
51
+ - lib/bewildr/control_type_additions/document_additions.rb
49
52
  - lib/bewildr/control_type_additions/list_additions.rb
50
53
  - lib/bewildr/control_type_additions/menu_additions.rb
51
54
  - lib/bewildr/control_type_additions/menu_item_additions.rb
@@ -70,25 +73,29 @@ rdoc_options: []
70
73
  require_paths:
71
74
  - lib
72
75
  required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
73
77
  requirements:
74
78
  - - ">="
75
79
  - !ruby/object:Gem::Version
80
+ hash: 3
76
81
  segments:
77
82
  - 0
78
83
  version: "0"
79
84
  required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
80
86
  requirements:
81
87
  - - ">="
82
88
  - !ruby/object:Gem::Version
89
+ hash: 3
83
90
  segments:
84
91
  - 0
85
92
  version: "0"
86
93
  requirements: []
87
94
 
88
95
  rubyforge_project:
89
- rubygems_version: 1.3.6
96
+ rubygems_version: 1.3.7
90
97
  signing_key:
91
98
  specification_version: 3
92
- summary: Test your WPF apps with (iron) ruby!
99
+ summary: Test WPF UI apps with (iron) ruby!
93
100
  test_files: []
94
101