watirmark 5.14.16

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.
Files changed (106) hide show
  1. data/app_generators/create_project/create_project_generator.rb +115 -0
  2. data/app_generators/create_project/templates/features/env.rb.erb +8 -0
  3. data/app_generators/create_project/templates/features/model_steps.rb.erb +9 -0
  4. data/app_generators/create_project/templates/features/post_error_steps.rb.erb +15 -0
  5. data/app_generators/create_project/templates/features/sample.feature.erb +5 -0
  6. data/app_generators/create_project/templates/features/site_steps.rb.erb +7 -0
  7. data/app_generators/create_project/templates/generators/controller.rb.erb +9 -0
  8. data/app_generators/create_project/templates/generators/generate.rb.erb +9 -0
  9. data/app_generators/create_project/templates/generators/model.rb.erb +7 -0
  10. data/app_generators/create_project/templates/generators/mvc_generator.rb.erb +100 -0
  11. data/app_generators/create_project/templates/generators/rbeautify.rb.erb +212 -0
  12. data/app_generators/create_project/templates/generators/view.rb.erb +16 -0
  13. data/app_generators/create_project/templates/generators/workflow_loader.rb.erb +1 -0
  14. data/app_generators/create_project/templates/library/base_controller.rb.erb +9 -0
  15. data/app_generators/create_project/templates/library/base_view.rb.erb +6 -0
  16. data/app_generators/create_project/templates/library/configuration.rb.erb +6 -0
  17. data/app_generators/create_project/templates/library/core_libraries.rb.erb +9 -0
  18. data/app_generators/create_project/templates/library/loader.rb.erb +23 -0
  19. data/app_generators/create_project/templates/library/page_load_checker.rb.erb +11 -0
  20. data/app_generators/create_project/templates/library/post_errors_checker.rb.erb +23 -0
  21. data/app_generators/create_project/templates/library/project_require_file.rb.erb +8 -0
  22. data/app_generators/create_project/templates/library/search_controller.rb.erb +12 -0
  23. data/app_generators/create_project/templates/library/workflows.rb.erb +0 -0
  24. data/app_generators/create_project/templates/project/config.yml.erb +3 -0
  25. data/app_generators/create_project/templates/project/gemfile.rb.erb +11 -0
  26. data/app_generators/create_project/templates/project/rakefile.rb.erb +21 -0
  27. data/bin/etapestry/Gemfile +11 -0
  28. data/bin/etapestry/config.yml +3 -0
  29. data/bin/etapestry/features/etapestry_home.feature +5 -0
  30. data/bin/etapestry/features/step_definitions/model_steps.rb +9 -0
  31. data/bin/etapestry/features/step_definitions/post_error_steps.rb +15 -0
  32. data/bin/etapestry/features/step_definitions/site_steps.rb +7 -0
  33. data/bin/etapestry/features/support/env.rb +8 -0
  34. data/bin/etapestry/generators/mvc/mvc_generator.rb +100 -0
  35. data/bin/etapestry/generators/mvc/rbeautify.rb +212 -0
  36. data/bin/etapestry/generators/mvc/templates/controller.rb.erb +9 -0
  37. data/bin/etapestry/generators/mvc/templates/model.rb.erb +7 -0
  38. data/bin/etapestry/generators/mvc/templates/view.rb.erb +16 -0
  39. data/bin/etapestry/generators/mvc/templates/workflow_loader.rb.erb +1 -0
  40. data/bin/etapestry/lib/etapestry.rb +8 -0
  41. data/bin/etapestry/lib/etapestry/checkers/page_load_checker.rb +11 -0
  42. data/bin/etapestry/lib/etapestry/checkers/post_errors_checker.rb +23 -0
  43. data/bin/etapestry/lib/etapestry/configuration.rb +6 -0
  44. data/bin/etapestry/lib/etapestry/core_libraries.rb +9 -0
  45. data/bin/etapestry/lib/etapestry/loader.rb +23 -0
  46. data/bin/etapestry/lib/etapestry/site/base_controller.rb +9 -0
  47. data/bin/etapestry/lib/etapestry/site/base_view.rb +6 -0
  48. data/bin/etapestry/lib/etapestry/site/search_controller.rb +12 -0
  49. data/bin/etapestry/lib/etapestry/workflows.rb +0 -0
  50. data/bin/etapestry/rakefile.rb +21 -0
  51. data/bin/etapestry/script/generate.rb +9 -0
  52. data/bin/twitter/features/hashtag_search.feature +93 -0
  53. data/bin/twitter/features/step_definitions/hashtag_steps.rb +9 -0
  54. data/bin/twitter/lib/twitter/workflows/search/result_controller.rb +13 -0
  55. data/bin/twitter/lib/twitter/workflows/search/result_model.rb +5 -0
  56. data/bin/twitter/lib/twitter/workflows/search/result_view.rb +19 -0
  57. data/bin/watirmark +10 -0
  58. data/lib/watirmark.rb +26 -0
  59. data/lib/watirmark/at_exit.rb +13 -0
  60. data/lib/watirmark/configuration.rb +201 -0
  61. data/lib/watirmark/controller/actions.rb +172 -0
  62. data/lib/watirmark/controller/assertions.rb +116 -0
  63. data/lib/watirmark/controller/controller.rb +191 -0
  64. data/lib/watirmark/controller/dialogs.rb +33 -0
  65. data/lib/watirmark/controller/matcher.rb +19 -0
  66. data/lib/watirmark/cucumber/cuke_helper.rb +150 -0
  67. data/lib/watirmark/cucumber/email_helper.rb +103 -0
  68. data/lib/watirmark/cucumber/env.rb +9 -0
  69. data/lib/watirmark/cucumber/hooks.rb +16 -0
  70. data/lib/watirmark/cucumber/model_helper.rb +34 -0
  71. data/lib/watirmark/cucumber/transforms.rb +55 -0
  72. data/lib/watirmark/exceptions.rb +15 -0
  73. data/lib/watirmark/extensions/ruby_extensions.rb +129 -0
  74. data/lib/watirmark/extensions/webdriver_extensions.rb +150 -0
  75. data/lib/watirmark/formatters/snapshot_formatter.rb +23 -0
  76. data/lib/watirmark/loader.rb +87 -0
  77. data/lib/watirmark/model.rb +3 -0
  78. data/lib/watirmark/models/cucumber_helper.rb +49 -0
  79. data/lib/watirmark/models/debug_methods.rb +21 -0
  80. data/lib/watirmark/models/default_values.rb +21 -0
  81. data/lib/watirmark/models/factory.rb +168 -0
  82. data/lib/watirmark/models/factory_method_generators.rb +84 -0
  83. data/lib/watirmark/models/factory_methods.rb +72 -0
  84. data/lib/watirmark/models/trait.rb +35 -0
  85. data/lib/watirmark/models/upload_csv.rb +24 -0
  86. data/lib/watirmark/page/keyed_element.rb +63 -0
  87. data/lib/watirmark/page/page.rb +50 -0
  88. data/lib/watirmark/page/page_definition.rb +187 -0
  89. data/lib/watirmark/page/process_page.rb +112 -0
  90. data/lib/watirmark/page/radio_maps.rb +53 -0
  91. data/lib/watirmark/profile.rb +22 -0
  92. data/lib/watirmark/rake/smoketest.rb +17 -0
  93. data/lib/watirmark/screenshot.rb +127 -0
  94. data/lib/watirmark/session.rb +115 -0
  95. data/lib/watirmark/version.rb +5 -0
  96. data/spec/assertions_spec.rb +95 -0
  97. data/spec/config_spec.rb +82 -0
  98. data/spec/controller_actions_spec.rb +91 -0
  99. data/spec/controller_spec.rb +426 -0
  100. data/spec/controllers_and_models_spec.rb +52 -0
  101. data/spec/model_factory_spec.rb +568 -0
  102. data/spec/model_traits_spec.rb +141 -0
  103. data/spec/page_spec.rb +127 -0
  104. data/spec/process_page_spec.rb +163 -0
  105. data/spec/spec_helper.rb +17 -0
  106. metadata +238 -0
@@ -0,0 +1,16 @@
1
+ module <%= name.camelize %>
2
+ <%%= create_modules %>
3
+ class <%%= name.camelize %>View < BaseView
4
+ keyword(:keyword_name) { browser.text_field(:id, 'element_id') }
5
+
6
+ def home(model)
7
+ end
8
+
9
+ def create(model)
10
+ end
11
+
12
+ def edit(model)
13
+ end
14
+ end
15
+ <%%= create_module_end %>
16
+ end
@@ -0,0 +1 @@
1
+ <%= name.camelize %>::Loader.load_product '<%%= product.downcase %>'
@@ -0,0 +1,9 @@
1
+ module <%= name.camelize %>
2
+ class BaseController < Watirmark::WebPage::Controller
3
+
4
+ # default way of submitting a form
5
+ def submit
6
+ # @view.save_button.click
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module <%= name.camelize %>
2
+ class BaseView < Watirmark::Page
3
+ class << self
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'watirmark/configuration'
2
+
3
+ Watirmark::Configuration.instance.defaults = {
4
+ :configfile => "#{File.dirname(__FILE__) + '/../..'}/config.yml",
5
+ }
6
+ Watirmark::Configuration.instance.reload
@@ -0,0 +1,9 @@
1
+ require '<%= name.downcase %>/site/base_view'
2
+ require '<%= name.downcase %>/site/base_controller'
3
+ require '<%= name.downcase %>/site/search_controller'
4
+ Watirmark.loader do
5
+ base_directory File.dirname(__FILE__)
6
+ product '<%= name.camelize %>'
7
+ load_files 'checkers/**/*.rb'
8
+ end
9
+
@@ -0,0 +1,23 @@
1
+ require 'watirmark/loader'
2
+ module <%= name.camelize %>
3
+ class Loader
4
+ class << self
5
+ @@loaded = {}
6
+
7
+ def load_workflow(name)
8
+ load_files name, "*{_view}.rb"
9
+ load_files name, "*{_model}.rb"
10
+ load_files name, "*{_controller}.rb"
11
+ load_files name, "*.rb"
12
+ end
13
+
14
+ def load_files(name, files)
15
+ Watirmark.loader do
16
+ base_directory File.dirname(__FILE__)
17
+ product '<%= name.camelize %>'
18
+ load_files "workflows/#{name}#{files}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ module Watirmark
2
+ class Session
3
+
4
+ # put in here the appropriate waits
5
+ # to verify that the page has loaded completely, if your app has javascript-loaded content
6
+ def self.page_load
7
+ Watir::Wait.until { Page.browser.url != "about:blank" }
8
+ end
9
+ Watirmark::Session::POST_WAIT_CHECKERS << Proc.new { Watirmark::Session::page_load }
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ require 'watirmark/session'
2
+
3
+ module Watirmark
4
+ class Session
5
+
6
+ # Post errors are basically any error messages that
7
+ # appear to the user when a form submission fails. This catches that
8
+ # error and allows the cucumber to catch the error (@@buffer_post_failure)
9
+ # or just throw an exception when an error is seen after a post
10
+ def self.post_errors
11
+ #if Page.browser.table(:class, 'error').present?
12
+ # message = Page.browser.table(:class, 'error').text
13
+ # if @@buffer_post_failure
14
+ # @@post_failure = message.strip
15
+ # else
16
+ # raise Watirmark::PostFailure, message.strip
17
+ # end
18
+ #end
19
+ end
20
+
21
+ Watirmark::Session::POST_WAIT_CHECKERS << Proc.new { Watirmark::Session::post_errors }
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ module <%= name.camelize %>; end
2
+
3
+ require '<%= name.downcase %>/configuration'
4
+ require 'watirmark'
5
+ require '<%= name.downcase %>/loader'
6
+ require '<%= name.downcase %>/core_libraries'
7
+ require '<%= name.downcase %>/workflows'
8
+
@@ -0,0 +1,12 @@
1
+ module <%= name.camelize %>
2
+ class SearchController < BaseController
3
+
4
+ def current_record_visible?
5
+ raise "Method needs to be defined in the subclass and return a true/false value"
6
+ end
7
+
8
+ def populate_data
9
+ super unless current_record_visible?
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ hostname: www.<%= name.downcase %>.com
2
+ webdriver: firefox
3
+ default_firefox_profile: default
@@ -0,0 +1,11 @@
1
+ source "http://gemcutter.org"
2
+ source "http://gemserver.qa.convioanalyticstest.net:8808"
3
+
4
+ gem 'watirmark'
5
+ gem 'watir-webdriver', '0.6.1.6'
6
+ gem 'rspec'
7
+ gem 'rake'
8
+ gem 'builder'
9
+ gem 'cucumber'
10
+ gem 'gherkin'
11
+ gem 'bundler'
@@ -0,0 +1,21 @@
1
+ $: << File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ # Run a bundle install if running from Jenkins
4
+ begin
5
+ sh "bundle install" if File.dirname(__FILE__) =~ /\/(hudson|mnt)\/workspace\//
6
+ rescue Gem::RemoteFetcher::FetchError
7
+ puts "Unable to connect - retrying #{Time.now}"
8
+ retry
9
+ end
10
+
11
+ require 'bundler/setup'
12
+ require 'cucumber/rake/task'
13
+
14
+ module RakeHelper
15
+ def self.cucumber_task(task_name, files=nil)
16
+ Cucumber::Rake::Task.new(task_name) do |t|
17
+ t.cucumber_opts = "-r features #{FileList[files]} -b --format html -o reports/report.html --format pretty"
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,11 @@
1
+ source "http://gemcutter.org"
2
+ source "http://gemserver.qa.convioanalyticstest.net:8808"
3
+
4
+ gem 'watirmark'
5
+ gem 'watir-webdriver', '0.6.1.6'
6
+ gem 'rspec'
7
+ gem 'rake'
8
+ gem 'builder'
9
+ gem 'cucumber'
10
+ gem 'gherkin'
11
+ gem 'bundler'
@@ -0,0 +1,3 @@
1
+ hostname: www.etapestry.com
2
+ webdriver: firefox
3
+ default_firefox_profile: default
@@ -0,0 +1,5 @@
1
+ Feature: This is a sample feature file to make sure you have everything set up properly
2
+
3
+ Scenario: Navigate to the site by hostname
4
+ Given I go to the home page
5
+ Then the url should contain "etapestry.com"
@@ -0,0 +1,9 @@
1
+ # There are cases where we want a bare model,
2
+ # For example in the API we can use the model to generate the defaults for the API call
3
+ When /I create a model (\[[^\]]+\])$/ do |model|
4
+ end
5
+
6
+ When /I (create|update) a model (\[[^\]]+\]) with values$/ do |action, model, table|
7
+ update_model(model, table)
8
+ end
9
+
@@ -0,0 +1,15 @@
1
+ # Exact matches
2
+ Then /^I should see the error: '?"?([^\/].*)"?'?$/ do |error|
3
+ # Replace carriage returns with a space to make it easier to declare the error
4
+ if Watirmark::Session.instance.post_failure
5
+ Watirmark::Session.instance.post_failure.gsub(/[\r\n]+/, ' ').strip.should == error.strip
6
+ else
7
+ 'No POST failure seen!'.should == error
8
+ end
9
+ end
10
+
11
+ # Pattern matches
12
+ Then /^I should see the error: \/(.+)\/$/ do |error|
13
+ Watirmark::Session.instance.post_failure.gsub(/[\r\n]+/, ' ').should =~ /#{error.gsub!(/[\r\n]+/, ' ')}/
14
+ end
15
+
@@ -0,0 +1,7 @@
1
+ Given /I go to the home page/ do
2
+ Page.browser.goto "www.etapestry.com"
3
+ end
4
+
5
+ Then /the url should contain "(.*?)"/ do |url|
6
+ Page.browser.url.should match(url)
7
+ end
@@ -0,0 +1,8 @@
1
+ dir = File.join(File.dirname(__FILE__))
2
+ $: << File.expand_path("#{dir}/../../lib")
3
+ $: << File.expand_path(dir)
4
+
5
+ require 'etapestry'
6
+ require 'watirmark/cucumber/env'
7
+
8
+ include Etapestry
@@ -0,0 +1,100 @@
1
+ require 'rubigen'
2
+ require 'active_support/inflector'
3
+ require_relative 'rbeautify'
4
+
5
+ class MvcGenerator < RubiGen::Base
6
+ attr_reader :product, :name
7
+
8
+ def initialize(runtime_args, runtime_options = {})
9
+ super
10
+ usage if args.empty?
11
+ @product = args.shift
12
+ @name = args.shift
13
+ usage unless @name && @product
14
+ @destination_root = File.expand_path(File.dirname(__FILE__) + '/../../')
15
+ extract_options
16
+ end
17
+
18
+ def workflow_directory
19
+ "lib/etapestry/workflows/#{@product}"
20
+ end
21
+
22
+ def manifest
23
+ record do |m|
24
+ create_directories(m)
25
+ add_mvc_stubs m
26
+ add_loader
27
+ end
28
+ end
29
+
30
+ def add_mvc_stubs m
31
+ m.template "model.rb.erb", File.join(workflow_directory, "#{@name}_model.rb")
32
+ m.template "view.rb.erb", File.join(workflow_directory,"#{@name}_view.rb")
33
+ m.template "controller.rb.erb", File.join(workflow_directory,"#{@name}_controller.rb")
34
+ end
35
+
36
+ def workflow_exists?
37
+ File.directory? "../#{workflow_directory}"
38
+ end
39
+
40
+ def add_rake_task
41
+ append_to_file "../rakefile.rb" do |f|
42
+ f.puts "RakeHelper.cucumber_task(:#{@product}, \"features/#{@product}/**/*.feature\")"
43
+ end
44
+ end
45
+
46
+ def add_loader
47
+ append_to_file "../lib/etapestry/workflows.rb" do |f|
48
+ f.puts "Etapestry::Loader.load_workflow '#{@product.downcase}/#{@name.downcase}'"
49
+ end
50
+ end
51
+
52
+ def append_to_file name, &block
53
+ File.open(name, 'a+') {|f| yield f}
54
+ end
55
+
56
+ def create_directories(m)
57
+ m.directory workflow_directory
58
+ end
59
+
60
+ def create_modules
61
+ @product.split('/').map{|x| "module #{x.camelize}\n"}.join.strip
62
+ end
63
+
64
+ def create_module_end
65
+ @product.split('/').map{|x| "end\n"}.join.strip
66
+ end
67
+
68
+ protected
69
+ def banner
70
+ <<-EOS
71
+ USAGE: #{spec.name} path/for/your/test/mvc workflow_directory name [options]
72
+ EOS
73
+ end
74
+
75
+ def after_generate
76
+ mvc_file_path = "#{@destination_root}/#{workflow_directory}/#{@name}"
77
+ RBeautify.new({}).beautify_file("#{mvc_file_path}_model.rb")
78
+ RBeautify.new({}).beautify_file("#{mvc_file_path}_view.rb")
79
+ RBeautify.new({}).beautify_file("#{mvc_file_path}_controller.rb")
80
+ end
81
+
82
+ def add_options!(opts)
83
+ opts.separator ''
84
+ opts.separator 'Options:'
85
+ # For each option below, place the default
86
+ # at the top of the file next to "default_options"
87
+ # opts.on("-a", "--author=\"Your Name\"", String,
88
+ # "Some comment about this option",
89
+ # "Default: none") { |options[:author]| }
90
+ opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
91
+ end
92
+
93
+ def extract_options
94
+ # for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
95
+ # Templates can access these value via the attr_reader-generated methods, but not the
96
+ # raw instance variable value.
97
+ # @author = options[:author]
98
+ end
99
+
100
+ end
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+
4
+ =begin
5
+ /***************************************************************************
6
+ * Copyright (C) 2008, Paul Lutus *
7
+ * *
8
+ * This program is free software; you can redistribute it and/or modify *
9
+ * it under the terms of the GNU General Public License as published by *
10
+ * the Free Software Foundation; either version 2 of the License, or *
11
+ * (at your option) any later version. *
12
+ * *
13
+ * This program is distributed in the hope that it will be useful, *
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16
+ * GNU General Public License for more details. *
17
+ * *
18
+ * You should have received a copy of the GNU General Public License *
19
+ * along with this program; if not, write to the *
20
+ * Free Software Foundation, Inc., *
21
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22
+ ***************************************************************************/
23
+ =end
24
+
25
+ PVERSION = "Version 2.9, 10/24/2008"
26
+
27
+ class RBeautify
28
+
29
+ # indent regexp tests
30
+
31
+ IndentExp = [
32
+ /^module\b/,
33
+ /^class\b/,
34
+ /^if\b/,
35
+ /(=\s*|^)until\b/,
36
+ /(=\s*|^)for\b/,
37
+ /^unless\b/,
38
+ /(=\s*|^)while\b/,
39
+ /(=\s*|^)begin\b/,
40
+ /(^| )case\b/,
41
+ /\bthen\b/,
42
+ /^rescue\b/,
43
+ /^def\b/,
44
+ /\bdo\b/,
45
+ /^else\b/,
46
+ /^elsif\b/,
47
+ /^ensure\b/,
48
+ /\bwhen\b/,
49
+ /\{[^\}]*$/,
50
+ /\[[^\]]*$/
51
+ ]
52
+
53
+ # outdent regexp tests
54
+
55
+ OutdentExp = [
56
+ /^rescue\b/,
57
+ /^ensure\b/,
58
+ /^elsif\b/,
59
+ /^end\b/,
60
+ /^else\b/,
61
+ /\bwhen\b/,
62
+ /^[^\{]*\}/,
63
+ /^[^\[]*\]/
64
+ ]
65
+
66
+ # user-customizable values
67
+ OPTIONS = {
68
+ tab_string: ' ',
69
+ tab_size: 2
70
+ }
71
+
72
+ def initialize(options)
73
+ options = OPTIONS.merge(options)
74
+ @tab_string, @tab_size = options[:tab_string], options[:tab_size]
75
+ end
76
+
77
+ def rb_make_tab(tab)
78
+ tab < 0 ? "" : (@tab_string * @tab_size * tab)
79
+ end
80
+
81
+ def rb_add_line(line,tab)
82
+ line.strip!
83
+ line = rb_make_tab(tab) + line if line.length > 0
84
+ line
85
+ end
86
+
87
+ def beautify_string(source, path = "")
88
+ comment_block = false
89
+ in_here_doc = false
90
+ here_doc_term = ""
91
+ program_end = false
92
+ multiLine_array = []
93
+ multiLine_str = ""
94
+ tab = 0
95
+ output = []
96
+ source.each_line do |line|
97
+ line.chomp!
98
+ if !program_end
99
+ # detect program end mark
100
+ if line =~ /^__END__$/
101
+ program_end = true
102
+ else
103
+ # combine continuing lines
104
+ if !(line =~ /^\s*#/) && line =~ /[^\\]\\\s*$/
105
+ multiLine_array.push line
106
+ multiLine_str += line.sub(/^(.*)\\\s*$/,"\\1")
107
+ next
108
+ end
109
+
110
+ # add final line
111
+ if multiLine_str.length > 0
112
+ multiLine_array.push line
113
+ multiLine_str += line.sub(/^(.*)\\\s*$/,"\\1")
114
+ end
115
+
116
+ tline = ((multiLine_str.length > 0) ? multiLine_str : line).strip
117
+ if tline =~ /^=begin/
118
+ comment_block = true
119
+ end
120
+ if in_here_doc
121
+ in_here_doc = false if tline =~ %r{\s*#{here_doc_term}\s*}
122
+ else # not in here_doc
123
+ if tline =~ %r{=\s*<<}
124
+ here_doc_term = tline.sub(%r{.*=\s*<<-?\s*([_|\w]+).*},"\\1")
125
+ in_here_doc = here_doc_term.size > 0
126
+ end
127
+ end
128
+ end
129
+ end
130
+ if comment_block || program_end || in_here_doc
131
+ # add the line unchanged
132
+ output << line
133
+ else
134
+ comment_line = (tline =~ /^#/)
135
+ if !comment_line
136
+ # throw out sequences that will
137
+ # only sow confusion
138
+ while tline.gsub!(/\{[^\{]*?\}/,"")
139
+ end
140
+ while tline.gsub!(/\[[^\[]*?\]/,"")
141
+ end
142
+ while tline.gsub!(/'.*?'/,"")
143
+ end
144
+ while tline.gsub!(/".*?"/,"")
145
+ end
146
+ while tline.gsub!(/\`.*?\`/,"")
147
+ end
148
+ while tline.gsub!(/\([^\(]*?\)/,"")
149
+ end
150
+ while tline.gsub!(/\/.*?\//,"")
151
+ end
152
+ while tline.gsub!(/%r(.).*?\1/,"")
153
+ end
154
+ # delete end-of-line comments
155
+ tline.sub!(/#[^\"]+$/,"")
156
+ # convert quotes
157
+ tline.gsub!(/\\\"/,"'")
158
+ OutdentExp.each do |re|
159
+ if tline =~ re
160
+ tab -= 1
161
+ break
162
+ end
163
+ end
164
+ end
165
+ if multiLine_array.length > 0
166
+ multiLine_array.each do |ml|
167
+ output << rb_add_line(ml,tab)
168
+ end
169
+ multiLine_array.clear
170
+ multiLine_str = ""
171
+ else
172
+ output << rb_add_line(line,tab)
173
+ end
174
+ if !comment_line
175
+ IndentExp.each do |re|
176
+ if tline =~ re && !(tline =~ /\s+end\s*$/)
177
+ tab += 1
178
+ break
179
+ end
180
+ end
181
+ end
182
+ end
183
+ if tline =~ /^=end/
184
+ comment_block = false
185
+ end
186
+ end
187
+ error = (tab != 0)
188
+ STDERR.puts "Error: indent/outdent mismatch: #{tab}." if error
189
+ return output.join("\n") + "\n",error
190
+ end # beautify_string
191
+
192
+ def beautify_file(path)
193
+ error = false
194
+
195
+ if path == '-' # stdin source
196
+ source = STDIN.read
197
+ dest,error = beautify_string(source,"stdin")
198
+ print dest
199
+ else # named file source
200
+ source = File.read(path)
201
+ dest,error = beautify_string(source,path)
202
+
203
+ if source != dest
204
+ # make a backup copy
205
+ File.open(path + "~","w") { |f| f.write(source) }
206
+ # overwrite the original
207
+ File.open(path,"w") { |f| f.write(dest) }
208
+ end
209
+ end
210
+ error
211
+ end # beautify_file
212
+ end # module RBeautify