bewildr 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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