class Sir::Parser
Sir::Parser
is class that parse html and generate commands that may be sent into Capybara
.
@example
Sir::Parser.new('path/to/file').parse! #=> [ { command: 'select', args: [ { id: 'ccid', label: /expire/ } ] } ]
Constants
- ATTRIBUTE
- EQUATION
- EQUATION_WITH_REGEX
- JS
- METHODS
Map selenium methods to wrapper's ones.
- NO_EQUATIONS_METHODS
- PSEUDO_SELECTOR
- VARIABLE
Attributes
Public Class Methods
# File lib/sir/parser.rb, line 15 def initialize(path, initial_state = nil, wrapper = nil) @path = path @document = Nokogiri::HTML File.read path @wrapper = wrapper || Sir::Wrapper.new @wrapper.state = initial_state if initial_state end
Make it possible to run command right from Sir::Parser
.
# File lib/sir/parser.rb, line 24 def self.run!(path, initial_state = {}, wrapper = nil) new(path, initial_state, wrapper).run end
Public Instance Methods
Get commands from html structure and parse them.
# File lib/sir/parser.rb, line 78 def commands document.css('tbody tr') end
Parse one command. @param c [Nokogiri::Element] one command on selenium language.
# File lib/sir/parser.rb, line 67 def get_command(c) if path = external_script_link(c) { command: 'run', args: [full_path(path)] } elsif title?(c) nil else parse_command(*c.css('td').map(&:text)) end end
Parse command from array to hash
@param command [String] selenium command name @param args [Array] selenium arguments
@example
parse_command(*["open", "${BOX}/application", ""]) #=> { command: 'visit', args: ['#http://value/of/box/application'] }
# File lib/sir/parser.rb, line 91 def parse_command(command, *args) method = METHODS[command] fail "Unrecognized command: #{command}" if method.nil? arguments = args.reject(&:empty?).map do |line| with_vars = parse_js(replace_variables(line)) next with_vars if NO_EQUATIONS_METHODS.include?(method) EQUATION_WITH_REGEX.match(with_vars) ? parse_equation_with_regex(with_vars) : parse_equation(with_vars) end.flatten { command: method, args: arguments } end
Run commands from file. It makes interpretation itself.
# File lib/sir/parser.rb, line 31 def run result = commands.inject([]) do |r, x| begin command = get_command x next (r) unless command r << wrapper.send_command(command) rescue NoMethodError => e if command[:args].last == "*[aria-label=Delete]" # workaround for gmail return { success: false, output: (r << command), } else binding.pry return { success: false, output: (r << command), error: { message: e.message, backtrace: e.backtrace } } end rescue => e binding.pry return { success: false, output: (r << command), error: { message: e.message, backtrace: e.backtrace } } end end failed = result.any? { |x| x[:command] == 'run' && x[:result][:success] == false } { success: !failed, output: result } end
Protected Instance Methods
Search link to other file in tr. @params tr [Nokogiri::Node] if fact any Nokogiri node.
@returns nil when no link founded. @returns String with link if founded.
# File lib/sir/parser.rb, line 111 def external_script_link(tr) tr.css('td a').map { |l| l['href'] }.first end
Expand path relative to path of file that we interpret.
@params link [String] relative path @returns [String] full path
# File lib/sir/parser.rb, line 126 def full_path(link) File.expand_path('../' + link, @path) end
Parse attribute. In selenium attribute is written like 'link@href'.
# File lib/sir/parser.rb, line 168 def parse_attribute(line) match_data = ATTRIBUTE.match(line) match_data ? match_data[1..2] : [line] end
Split equation into variable and value.
# File lib/sir/parser.rb, line 147 def parse_equation(line) match_data = EQUATION.match(line) return line unless match_data left = match_data[1].to_sym right = parse_pseudo_selector(match_data[2]) right = Array === right ? right : parse_attribute(match_data[2]) [left, *right] end
# File lib/sir/parser.rb, line 156 def parse_equation_with_regex(line) match_data = EQUATION_WITH_REGEX.match(line) match_data ? [match_data[1].to_sym, /#{match_data[2]}/] : line end
# File lib/sir/parser.rb, line 161 def parse_js(line) match_data = JS.match(line) match_data ? ExecJS.eval(match_data[1]).to_s : line end
Parse pseudo selector. For example: “div span:contains('Purchase')”
# File lib/sir/parser.rb, line 176 def parse_pseudo_selector(line) match_data = PSEUDO_SELECTOR.match(line) replace_pseudo = { 'contains' => :text } return line unless match_data [ match_data[1], { (replace_pseudo[match_data[2]] || match_data[2]).to_sym => match_data[3] } ] end
Replace variables that we have in state. Pattern of variable is '${var}'.
# File lib/sir/parser.rb, line 140 def replace_variables(line) line.scan(VARIABLE).flatten .reduce(line) { |r, x| r.gsub("${#{x}}", (wrapper.state[x] || '')) } end
Check if tr is title. Title is written with bold font.
# File lib/sir/parser.rb, line 117 def title?(tr) !!tr.css('td b').text[0] end