vapir-firefox 1.9.0 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -187,7 +187,7 @@ module Vapir
187
187
  # socket may be dead, and you want a new one. a warning will be printed if this occurs.
188
188
  def self.firefox_socket(options={}) # :nodoc:
189
189
  if options[:reset] || !(class_variable_defined?('@@firefox_socket') && @@firefox_socket)
190
- initialize_firefox_socket(options[:socket_class], options[:socket_options])
190
+ initialize_firefox_socket(options[:socket_class] || firefox_socket_class, options[:socket_options] || firefox_socket_class_options)
191
191
  end
192
192
  if options[:reset_if_dead]
193
193
  begin
@@ -268,7 +268,7 @@ module Vapir
268
268
 
269
269
  @pid = begin
270
270
  self.pid
271
- rescue NotImplementedError
271
+ rescue CannotHandlePid
272
272
  nil
273
273
  end
274
274
 
@@ -282,7 +282,6 @@ module Vapir
282
282
  find_window(how, what)
283
283
  end
284
284
  end
285
- set_browser_document
286
285
  else
287
286
  open_window
288
287
  end
@@ -294,8 +293,8 @@ module Vapir
294
293
  wait if options[:wait]
295
294
  end
296
295
 
297
- def mozilla_window_class_name
298
- 'MozillaUIWindowClass'
296
+ def mozilla_window_class_names
297
+ ['MozillaUIWindowClass', 'MozillaWindowClass']
299
298
  end
300
299
 
301
300
  def browser
@@ -413,7 +412,6 @@ module Vapir
413
412
  @document_object=browser_object.contentDocument
414
413
  @content_window_object=browser_object.contentWindow
415
414
  # note that browser_window_object.content is the same thing, but simpler to refer to stuff on browser_object since that is updated by the nsIWebProgressListener below
416
- @body_object=document_object.body
417
415
  @browser_objects[:requests_in_progress]=[]
418
416
  @requests_in_progress=@browser_objects[:requests_in_progress].to_array
419
417
  @browser_objects[:unmatched_stopped_requests_count]=0
@@ -481,7 +479,9 @@ module Vapir
481
479
  attr_reader :content_window_object
482
480
  attr_reader :browser_object
483
481
  attr_reader :document_object
484
- attr_reader :body_object
482
+ def body_object
483
+ document_object.body
484
+ end
485
485
 
486
486
  def updated_at
487
487
  Time.at(@updated_at_epoch_ms.val/1000.0)+@updated_at_offset
@@ -517,7 +517,7 @@ module Vapir
517
517
  end
518
518
  end
519
519
 
520
- @browser_window_object=@browser_object=@document_object=@content_window_object=@body_object=nil
520
+ @browser_window_object=@browser_object=@document_object=@content_window_object=nil
521
521
  if @self_launched_browser && firefox_socket && !self.class.window_objects.any?{ true }
522
522
  quit_browser(:force => false)
523
523
  end
@@ -540,7 +540,7 @@ module Vapir
540
540
 
541
541
  pid = @pid || begin
542
542
  self.pid
543
- rescue NotImplementedError
543
+ rescue CannotHandlePid
544
544
  nil
545
545
  end
546
546
 
@@ -557,20 +557,24 @@ module Vapir
557
557
 
558
558
  wait_for_process_exit(pid)
559
559
 
560
- @browser_window_object=@browser_object=@document_object=@content_window_object=@body_object=nil
560
+ @browser_window_object=@browser_object=@document_object=@content_window_object=nil
561
561
  nil
562
562
  end
563
563
 
564
+ # class representing an inability to either retrieve or check the status of firefox's pid
565
+ class CannotHandlePid < StandardError; end
566
+
564
567
  # returns the pid of the currently-attached Firefox process.
565
568
  #
566
569
  # This only works on Firefox >= 3.6, on platforms supported (see #current_os), and raises
567
- # NotImplementedError if it can't get the pid.
570
+ # CannotHandlePid if it can't get the pid.
568
571
  def pid
569
572
  begin
573
+ raise CannotHandlePid unless firefox_socket.host == 'localhost'
570
574
  begin
571
575
  ctypes = firefox_socket.Components.utils.import("resource://gre/modules/ctypes.jsm").ctypes
572
576
  rescue FirefoxSocketJavascriptError
573
- raise NotImplementedError, "Firefox 3.6 or greater is required for this method.\n\nOriginal error from firefox: #{$!.class}: #{$!.message}", $!.backtrace
577
+ raise CannotHandlePid, "Firefox 3.6 or greater is required for this method.\n\nOriginal error from firefox: #{$!.class}: #{$!.message}", $!.backtrace
574
578
  end
575
579
  lib, pidfunction, abi = *case current_os
576
580
  when :macosx
@@ -588,7 +592,7 @@ module Vapir
588
592
  # see https://bugzilla.mozilla.org/show_bug.cgi?id=585175
589
593
  ['kernel32', 'GetCurrentProcessId', ctypes['winapi_abi'] || ctypes['stdcall_abi']]
590
594
  else
591
- raise NotImplementedError, "don't know how to get pid for #{current_os}"
595
+ raise CannotHandlePid, "don't know how to get pid for #{current_os}"
592
596
  end
593
597
  lib = ctypes.open(lib)
594
598
  begin
@@ -600,9 +604,16 @@ module Vapir
600
604
  end
601
605
  end
602
606
 
607
+ # returns the host which will be configured for a socket. same as firefox_socket.host,
608
+ # if that exist, but this is correct even if firefox_socket isn't initialized.
609
+ def firefox_socket_host
610
+ firefox_socket_class_options['host'] || firefox_socket_class.config.host
611
+ end
612
+
603
613
  # attempts to determine whether the given process is still running. will raise
604
- # NotImplementedError if it can't determine this.
614
+ # CannotHandlePid if it can't determine this.
605
615
  def process_running?(pid)
616
+ raise CannotHandlePid unless firefox_socket_host == 'localhost'
606
617
  case current_os
607
618
  when :windows
608
619
  kernel32 = Vapir::Firefox.instance_eval do # define this on the class for reuse
@@ -630,7 +641,7 @@ module Vapir
630
641
  `ps -p #{pid}`
631
642
  $? == 0
632
643
  else
633
- raise NotImplementedError
644
+ raise CannotHandlePid
634
645
  end
635
646
  end
636
647
 
@@ -800,12 +811,36 @@ module Vapir
800
811
 
801
812
  # the HTTP response status code for the currently loaded document
802
813
  def response_status_code
814
+ current_document_channel_object.responseStatus
815
+ end
816
+ # a hash of the response headers returned for the currently loaded document
817
+ def response_headers
818
+ firefox_socket.call_function(:channel => current_document_channel_object) do %Q{
819
+ var headers={};
820
+ channel.visitResponseHeaders({visitHeader: function(header, value){ headers[header]=value; }});
821
+ return headers;
822
+ }
823
+ end.val.freeze
824
+ end
825
+ # a hash of the request headers the browser sent for the currently loaded document
826
+ def request_headers
827
+ firefox_socket.call_function(:channel => current_document_channel_object) do %Q{
828
+ var headers={};
829
+ channel.visitRequestHeaders({visitHeader: function(header, value){ headers[header]=value; }});
830
+ return headers;
831
+ }
832
+ end.val.freeze
833
+ end
834
+ # a nsIHttpChannel for the currently loaded document - the browser's docShell.currentDocumentChannel
835
+ #
836
+ # see https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIHttpChannel
837
+ def current_document_channel_object
803
838
  channel = nil
804
839
  ::Waiter.try_for(8, :exception => nil) do
805
840
  channel=browser.browser_object.docShell.currentDocumentChannel
806
841
  channel.is_a?(JavascriptObject) && channel.instanceof(browser.firefox_socket.Components.interfaces.nsIHttpChannel) && channel.respond_to?(:responseStatus)
807
842
  end || raise(RuntimeError, "expected currentDocumentChannel to exist and be a nsIHttpChannel but it wasn't; was #{channel.is_a?(JavascriptObject) ? channel.toString : channel.inspect}")
808
- status = channel.responseStatus
843
+ channel
809
844
  end
810
845
 
811
846
  # Maximize the current browser window.
@@ -820,6 +855,7 @@ module Vapir
820
855
 
821
856
  # Waits for the page to get loaded.
822
857
  def wait(options={})
858
+ return unless config.wait
823
859
  return unless exists?
824
860
  unless options.is_a?(Hash)
825
861
  raise ArgumentError, "given options should be a Hash, not #{options.inspect} (#{options.class})\nold conflicting arguments of no_sleep or last_url are gone"
@@ -833,9 +869,9 @@ module Vapir
833
869
  # If the redirect is to a download attachment that does not reload this page, this
834
870
  # method will loop forever. Therefore, we need to ensure that if this method is called
835
871
  # twice with the same URL, we simply accept that we're done.
836
- url= document_object.URL
872
+ url= document_object['URL']
837
873
 
838
- if(url != options[:last_url])
874
+ if(url && url != options[:last_url])
839
875
  # check for meta redirects, except for redirects back to the same page (infinite
840
876
  # loop redirects).
841
877
  metas=document_object.getElementsByTagName 'meta'
@@ -876,7 +912,11 @@ module Vapir
876
912
  # - :format => a valid format. if :dc is :window, the default is 'png' ('jpeg' is also supported); if :dc is anything else, 'bmp' is both the
877
913
  # default and the only supported format.
878
914
  def screen_capture(filename, options = {})
879
- options = handle_options(options, :format => nil, :dc => :page)
915
+ if filename =~ /\.(\w+)\z/
916
+ extension = $1
917
+ file_format = %w(jpeg png).inject({'jpg' => 'jpeg'}){|h,f| h.merge(f => f) }[extension]
918
+ end
919
+ options = handle_options(options, :format => file_format, :dc => :page)
880
920
 
881
921
  if options[:dc] == :page
882
922
  options[:format] ||= 'png'
@@ -929,9 +969,8 @@ module Vapir
929
969
  fileOutputStream.init(nsFile, writeFlag | createFlag | truncateFlag, 0664, null);
930
970
  fileOutputStream.write(bytes, numBytes);
931
971
  fileOutputStream.close();
932
- document_element.removeChild(canvas);
933
972
  }
934
- catch(e)
973
+ finally
935
974
  { document_element.removeChild(canvas);
936
975
  }
937
976
  )
@@ -984,10 +1023,19 @@ module Vapir
984
1023
  raise NotImplementedError, "(need to know how to access windows registry on JRuby)" if RUBY_PLATFORM =~ /java/
985
1024
  require 'win32/registry'
986
1025
  lm = ::Win32::Registry::HKEY_LOCAL_MACHINE
987
- lm.open('SOFTWARE\Mozilla\Mozilla Firefox') do |reg|
988
- reg1 = lm.open("SOFTWARE\\Mozilla\\Mozilla Firefox\\#{reg.keys[0]}\\Main")
989
- if entry = reg1.find { |key, type, data| key =~ /pathtoexe/i }
990
- return entry.last
1026
+ lm.open('SOFTWARE\Mozilla\Mozilla Firefox') do |firefox_reg|
1027
+ firefox_reg.keys.map do |firefox_version_key|
1028
+ firefox_reg.open(firefox_version_key) do |firefox_version_reg|
1029
+ if firefox_version_reg.keys.include?('Main')
1030
+ firefox_version_reg.open('Main') do |firefox_version_main_reg|
1031
+ firefox_version_main_reg.map do |key, type, data|
1032
+ if key=='PathToExe'
1033
+ return data
1034
+ end
1035
+ end
1036
+ end
1037
+ end
1038
+ end
991
1039
  end
992
1040
  end
993
1041
  end
@@ -60,7 +60,7 @@ module Vapir
60
60
  # TODO: Provide ability to specify event parameters like keycode for key events, and click screen
61
61
  # coordinates for mouse events.
62
62
  def fire_event(event_type, options={})
63
- options={:wait => true, :highlight => true}.merge(options)
63
+ options={:wait => config.wait, :highlight => true}.merge(options)
64
64
  with_highlight(options) do
65
65
  event=create_event_object(event_type, options)
66
66
  if !options[:wait]
@@ -159,10 +159,10 @@ module Vapir
159
159
  # Options:
160
160
  # - :wait => true or false. If true, waits for the javascript call to return, and calls the #wait method.
161
161
  # If false, does not wait for the javascript to return and does not call #wait.
162
- # Default is true.
162
+ # Default is the current config.wait value (which is by default true).
163
163
  # - :highlight => true or false. Highlights the element while clicking if true. Default is true.
164
164
  def click(options={})
165
- options={:wait => true, :highlight => true}.merge(options)
165
+ options={:wait => config.wait, :highlight => true}.merge(options)
166
166
  result=nil
167
167
  with_highlight(options) do
168
168
  assert_enabled if respond_to?(:assert_enabled)
@@ -196,12 +196,12 @@ module Vapir
196
196
  # Takes options:
197
197
  # - :highlight => true or false. Highlights the element while clicking if true. Default is true.
198
198
  def click_no_wait(options={})
199
- click(options.merge(:wait => false))
199
+ with_config(:wait => false) { click(options) }
200
200
  end
201
201
 
202
202
  # Waits for the browser to finish loading, if it is loading. See Firefox#wait.
203
203
  def wait(options={})
204
- @container.wait(options)
204
+ @container.wait(options) if config.wait
205
205
  end
206
206
 
207
207
  # Checks this element and its parents for display: none or visibility: hidden, these are
@@ -240,7 +240,7 @@ class FirefoxSocket
240
240
  # immediately.
241
241
  def read_value(options={})
242
242
  options=options_from_config(options, {:timeout => :default_timeout, :read_size => :read_size}, [:length_before_value])
243
- received_data = []
243
+ # received_data = []
244
244
  value_string = ""
245
245
  size_to_read=options[:read_size]
246
246
  timeout=options[:timeout]
@@ -249,7 +249,13 @@ class FirefoxSocket
249
249
  # logger.add(-1) { "RECV_SOCKET is starting. timeout=#{timeout}" }
250
250
  while size_to_read > 0 && ensuring_extra_handled { @socket.ready_to_recv?(timeout) }
251
251
  data = ensuring_extra_handled { @socket.recv(size_to_read) }
252
- received_data << data
252
+
253
+ # if the peer has performed an orderly shutdown, recv returns a 0-length string.
254
+ if data.size==0
255
+ raise FirefoxSocketConnectionError, "The connection to Firefox has been closed."
256
+ end
257
+
258
+ # received_data << data
253
259
  value_string << data
254
260
  if @prompt && @expecting_prompt && utf8_length_safe(value_string) > @prompt.length
255
261
  if value_string =~ /\A#{Regexp.escape(@prompt)}/
@@ -280,11 +286,6 @@ class FirefoxSocket
280
286
  timeout=config.short_timeout
281
287
  end
282
288
  end
283
-
284
- # Kernel.select seems to indicate that a dead socket is ready to read, and returns endless blank strings to recv. rather irritating.
285
- if received_data.length >= 3 && received_data[-3..-1].all?{|rd| rd==''}
286
- raise FirefoxSocketConnectionError, "Socket seems to no longer be connected"
287
- end
288
289
  # logger.add(-1) { "RECV_SOCKET is continuing. timeout=#{timeout}; data=#{data.inspect}" }
289
290
  end
290
291
  # logger.debug { "RECV_SOCKET is done. received_data=#{received_data.inspect}; value_string=#{value_string.inspect}" }
@@ -143,7 +143,7 @@ class JavascriptObject
143
143
  def val_or_object(options={})
144
144
  options={:error_on_undefined=>true, :define_methods => self.class.always_define_methods}.merge(options)
145
145
  if function_result # calling functions multiple times is bad, so store in temp before figuring out what to do with it
146
- store_rand_object_key(firefox_socket.temp_object).val_or_object(options.merge(:error_on_undefined => false))
146
+ store_rand_temp.val_or_object(options.merge(:error_on_undefined => false))
147
147
  else
148
148
  # if we don't know our type, stick everything into one call to avoid multiple socket calls
149
149
  types_to_convert = ['boolean', 'number', 'string', 'null']
@@ -192,7 +192,7 @@ class JavascriptObject
192
192
  end
193
193
  end
194
194
  # does the work of #method_missing to determine whether to call a function what to return based
195
- # on the defined behavior of the given suffix. see #method_missing for more. information.
195
+ # on the defined behavior of the given suffix. see #method_missing for more information.
196
196
  def assign_or_call_or_val_or_object_by_suffix(suffix, *args)
197
197
  if suffix=='='
198
198
  assign(*args)
@@ -472,7 +472,9 @@ class JavascriptObject
472
472
  # in irb, mostly.
473
473
  def define_methods! # :nodoc:
474
474
  metaclass=(class << self; self; end)
475
- keys=firefox_socket.object("function(obj) { var keys=[]; for(var key in obj) { keys.push(key); } return keys; }").pass(self).val
475
+ # the following needs the try/catch because sometimes it raises NS_ERROR_NOT_AVAILABLE: Component is not available
476
+ # bug: https://bugzilla.mozilla.org/show_bug.cgi?id=683978
477
+ keys=firefox_socket.object("function(obj) { var keys=[]; try { for(var key in obj) { keys.push(key); } } catch(e) {} return keys; }").pass(self).val
476
478
 
477
479
  keys.grep(/\A[a-z_][a-z0-9_]*\z/i).reject{|k| self.class.method_defined?(k)}.each do |key|
478
480
  metaclass.send(:define_method, key) do |*args|
@@ -545,6 +547,9 @@ class JavascriptObject
545
547
  def to_function
546
548
  JavascriptFunction.new(self.ref, self.firefox_socket, :debug_name => debug_name)
547
549
  end
550
+ def to_simple_enumerator
551
+ JavascriptSimpleEnumerator.new(self.ref, self.firefox_socket, :debug_name => debug_name)
552
+ end
548
553
 
549
554
  # returns a ruby Hash. each key/value pair of this object
550
555
  # is represented in the returned hash.
@@ -649,6 +654,7 @@ class JavascriptDOMNode < JavascriptObject
649
654
  # call #dump(:recurse => n) to recurse down only n levels. default is to recurse all the way down the dom tree.
650
655
  def dump(options={})
651
656
  options={:recurse => nil, :level => 0}.merge(options)
657
+ options[:document] ||= self.ownerDocument
652
658
  next_options=options.merge(:recurse => options[:recurse] && (options[:recurse]-1), :level => options[:level]+1)
653
659
  result=(" "*options[:level]*2)+self.inspect+"\n"
654
660
  if options[:recurse]==0
@@ -657,6 +663,13 @@ class JavascriptDOMNode < JavascriptObject
657
663
  self.childNodes.to_array.each do |child|
658
664
  result+=child.to_dom.dump(next_options)
659
665
  end
666
+ anons = self.nodeType == 1 && options[:document].getAnonymousNodes(self)
667
+ if anons
668
+ result+=(" "*next_options[:level]*2)+"ANONYMOUS:\n"
669
+ anons.to_array.each do |child|
670
+ result+=child.to_dom.dump(next_options)
671
+ end
672
+ end
660
673
  end
661
674
  result
662
675
  end
@@ -734,3 +747,13 @@ class JavascriptFunction < JavascriptObject
734
747
  end
735
748
  end
736
749
  end
750
+
751
+ class JavascriptSimpleEnumerator < JavascriptObject
752
+ def each
753
+ stored = store_rand_temp
754
+ while stored.hasMoreElements
755
+ yield stored.getNext
756
+ end
757
+ end
758
+ include Enumerable
759
+ end
@@ -51,7 +51,7 @@ module Vapir
51
51
  # raise if no anonymous nodes are found (this is where the buttons are)
52
52
  anonymous_dialog_nodes=@modal_window.document.getAnonymousNodes(@modal_window.document.documentElement) || raise("Could not find anonymous nodes on which to look for buttons")
53
53
  xul_buttons=[]
54
- anonymous_dialog_nodes.to_array.each do |node|
54
+ anonymous_dialog_nodes.to_array.select{|node| node.nodeType == 1 }.each do |node|
55
55
  xul_buttons+=node.getElementsByTagName('xul:button').to_array.select do |button|
56
56
  Vapir::fuzzy_match(button.label, button_text)
57
57
  end
@@ -74,8 +74,8 @@ module Vapir
74
74
  assert_exists
75
75
  modal_window
76
76
  end
77
- def mozilla_window_class_name
78
- 'MozillaDialogClass'
77
+ def mozilla_window_class_names
78
+ ['MozillaDialogClass']
79
79
  end
80
80
  end
81
81
 
@@ -134,7 +134,8 @@ module Vapir
134
134
  end
135
135
 
136
136
  def wait(options=nil)
137
- ::Waiter.try_for(Firefox::ARBITRARY_TIMEOUT) do
137
+ return unless config.wait
138
+ ::Waiter.try_for(config.wait_timeout) do
138
139
  !browser_object.webProgress.isLoadingDocument
139
140
  end
140
141
  end
@@ -11,10 +11,12 @@ module Vapir
11
11
  end
12
12
 
13
13
  # evaluates a given javascript string in the context of the browser's content window. anything
14
- # that is a top-level variable on the window will be seen as a top-level variable in the
15
- # evaluated script.
14
+ # that is a top-level variable on the window (such as document or alert) will be seen as a
15
+ # top-level variable in the evaluated script.
16
16
  #
17
- # returns the last evaluated expression.
17
+ # returns the last evaluated expression. WARNING! DO NOT RUN #execute_script AGAINST UNTRUSTED
18
+ # PAGES! the resulting value has no security wrappers and could execute malicious code in a
19
+ # privileged context.
18
20
  #
19
21
  # raises an error if the given javascript errors.
20
22
  #
@@ -43,8 +45,17 @@ module Vapir
43
45
  # >> browser.execute_script('element.PercentLoaded()', :element => browser.element(:tag_name => 'embed').element_object)
44
46
  # => 100
45
47
  def execute_script(javascript, other_variables={})
46
- sandbox=firefox_socket.Components.utils.Sandbox(content_window_object)
47
- sandbox.window=content_window_object.window
48
+ # TODO: add tests for cross-context expando properties
49
+ xpcNativeWrapper = firefox_socket.root['XPCNativeWrapper']
50
+ unwrapped_window = if xpcNativeWrapper.respond_to?('unwrap')
51
+ xpcNativeWrapper.unwrap(content_window_object)
52
+ elsif content_window_object.respond_to?('wrappedJSObject')
53
+ content_window_object.wrappedJSObject
54
+ else
55
+ content_window_object.window
56
+ end
57
+ sandbox=firefox_socket.Components.utils.Sandbox(unwrapped_window, :wantXrays => false)
58
+ sandbox.window = unwrapped_window
48
59
  other_variables.each do |name, var|
49
60
  sandbox[name]=var
50
61
  end
@@ -1,5 +1,5 @@
1
1
  module Vapir
2
2
  class Firefox
3
- VERSION = '1.9.0'
3
+ VERSION = '1.10.0'
4
4
  end
5
5
  end
@@ -18,7 +18,7 @@ module Vapir
18
18
  begin
19
19
  candidates=::Waiter.try_for(2, :condition => proc{|ret| ret.size > 0}, :exception => nil) do
20
20
  WinWindow::All.select do |win|
21
- [mozilla_window_class_name].include?(win.class_name) && win.text==browser_window_object.document.title
21
+ mozilla_window_class_names.include?(win.class_name) && win.text==browser_window_object.document.title
22
22
  end
23
23
  end
24
24
  unless candidates.size==1
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vapir-firefox
3
3
  version: !ruby/object:Gem::Version
4
- hash: 51
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
- - 9
7
+ - 10
9
8
  - 0
10
- version: 1.9.0
9
+ version: 1.10.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Ethan
@@ -15,34 +14,30 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-08-04 00:00:00 -04:00
17
+ date: 2011-09-28 00:00:00 -04:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: vapir-common
23
22
  prerelease: false
24
23
  requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
24
  requirements:
27
25
  - - "="
28
26
  - !ruby/object:Gem::Version
29
- hash: 51
30
27
  segments:
31
28
  - 1
32
- - 9
29
+ - 10
33
30
  - 0
34
- version: 1.9.0
31
+ version: 1.10.0
35
32
  type: :runtime
36
33
  version_requirements: *id001
37
34
  - !ruby/object:Gem::Dependency
38
35
  name: json
39
36
  prerelease: false
40
37
  requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
42
38
  requirements:
43
39
  - - ">="
44
40
  - !ruby/object:Gem::Version
45
- hash: 3
46
41
  segments:
47
42
  - 0
48
43
  version: "0"
@@ -109,27 +104,23 @@ rdoc_options:
109
104
  require_paths:
110
105
  - lib
111
106
  required_ruby_version: !ruby/object:Gem::Requirement
112
- none: false
113
107
  requirements:
114
108
  - - ">="
115
109
  - !ruby/object:Gem::Version
116
- hash: 3
117
110
  segments:
118
111
  - 0
119
112
  version: "0"
120
113
  required_rubygems_version: !ruby/object:Gem::Requirement
121
- none: false
122
114
  requirements:
123
115
  - - ">="
124
116
  - !ruby/object:Gem::Version
125
- hash: 3
126
117
  segments:
127
118
  - 0
128
119
  version: "0"
129
120
  requirements:
130
121
  - Firefox browser with MozRepl or JSSH extension installed
131
122
  rubyforge_project:
132
- rubygems_version: 1.3.7
123
+ rubygems_version: 1.3.6
133
124
  signing_key:
134
125
  specification_version: 3
135
126
  summary: Library for automating the Firefox browser in Ruby