Ruby and Cucumber - What does this mean? "([^"]*)"$/ - ruby-on-rails

I am just trying to figure out what the below means in Ruby.
"([^"]*)"$/
I have the following code sample in Ruby using cucumber at the moment:
require "watir-webdriver"
require "rspec/expectations"
Given /^I have entered "([^"]*)" into the query$/ do |term|
#browser ||= Watir::Browser.new :firefox
#browser.goto "google.com"
#browser.text_field(:name => "q").set term
end
When /^I click "([^"]*)"$/ do |button_name|
#browser.button.click
end
Then /^I should see some results$/ do
#browser.div(:id => "resultStats").wait_until_present
#browser.div(:id => "resultStats").should exist
#browser.close
end
I understand at the moment that it is doing a logic check that a button has been clicked. I did a bit of research around and found the following for symbal meanings in Ruby (as I am new to Ruby)
? = method returns a boolean value.
$ = global variable
# = instance variable
## = class variable.
^ = bitwise XOR operator.
* = unpack array
I cannot see to find what the command does. I am trying to clarify exactly how functions are linked to variables and I think this is the final clue for me.
Many thanks in advance for any help.

It's a regular expression. The expression is contained between the "/" characters.
By way of an example and using your code:
/^I have entered "([^"]*)" into the query$/
is interpreted as a string that :
Matches the beginning of the line (^)
Matches "I have entered"
Matches a single quote
(") Matches everything that is not a quote ( ([^"]*) )
Matches " into the query"
Matches a single quote (")
Matches the end of the line $
See http://www.tutorialspoint.com/ruby/ruby_regular_expressions.htm for more information on Ruby and Regular expressions.

Related

How do I extract just a specific portion of a code snippet from multiple files, that may be different in different files

So what I am doing is iterating over various versions of snippet of code (for e.g. Associations.rb in Rails).
What I want to do is just extract one snippet of the code, for example the has_many method:
def has_many(name, scope = nil, options = {}, &extension)
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
Reflection.add_reflection self, name, reflection
end
At first I was thinking of just searching this entire file for the string def has_many and then saving everything between that string and end. The obvious issue with this, is that different versions of this file can have multiple end strings within the method.
For instance, whatever I come up with for the above snippet, should also work for this one too:
def has_many(association_id, options = {})
validate_options([ :foreign_key, :class_name, :exclusively_dependent, :dependent, :conditions, :order, :finder_sql ], options.keys)
association_name, association_class_name, association_class_primary_key_name =
associate_identification(association_id, options[:class_name], options[:foreign_key])
require_association_class(association_class_name)
if options[:dependent] and options[:exclusively_dependent]
raise ArgumentError, ':dependent and :exclusively_dependent are mutually exclusive options. You may specify one or the other.' # ' ruby-mode
elsif options[:dependent]
module_eval "before_destroy '#{association_name}.each { |o| o.destroy }'"
elsif options[:exclusively_dependent]
module_eval "before_destroy { |record| #{association_class_name}.delete_all(%(#{association_class_primary_key_name} = '\#{record.id}')) }"
end
define_method(association_name) do |*params|
force_reload = params.first unless params.empty?
association = instance_variable_get("##{association_name}")
if association.nil?
association = HasManyAssociation.new(self,
association_name, association_class_name,
association_class_primary_key_name, options)
instance_variable_set("##{association_name}", association)
end
association.reload if force_reload
association
end
# deprecated api
deprecated_collection_count_method(association_name)
deprecated_add_association_relation(association_name)
deprecated_remove_association_relation(association_name)
deprecated_has_collection_method(association_name)
deprecated_find_in_collection_method(association_name)
deprecated_find_all_in_collection_method(association_name)
deprecated_create_method(association_name)
deprecated_build_method(association_name)
end
Assuming that each value is stored as text in some column in my db.
How do I approach this, using Ruby's string methods or should I be approaching this another way?
Edit 1
Please note that this question relates specifically to string manipulation via using a Regex, without a parser.
As discussed, this should be done with a parser like Ripper.
However, to answer if it can be done with string methods, I will match the syntax with a regex, provided:
You can rely on indentation i.e. the string has the exact same characters before "def" and before "end".
There are no multiline strings in between that could simulate an "end" with the same indentation. That includes multine strings, HEREDOC, %{ }, etc.
Code
regex = /^
(\s*) # matches the indentation (we'll backreference later)
def\ +has_many\b # literal "def has_many" with a word boundary
(?:.*+\n)*? # match whole lines - as few as possible
\1 # matches the same indentation as the def line
end\b # literal "end"
/x
subject = %q|
def has_many(name, scope = nil, options = {}, &extension)
if association.nil?
instance_variable_set("##{association_name}", association)
end
end|
#Print matched text
puts subject.to_enum(:scan,regex).map {$&}
ideone demo
The regex relies on:
Capturing the whitespace (indentation) with the group (\s*),
followed by the literal def has_many.
It then consumes as few lines as it can with (?:.*+\n)*?.
Notice that .*+\n matches a whole line
and (?:..)*? repeats it 0 or more times. Also, the last ? makes the repetition lazy (as few as possible).
It will consume lines until it matches the following condition...
\1 is a backreference, storing the text matched in (1), i.e. the exact same indentation as the first line.
Followed by end obviously.
Test in Rubular

Replacing {phrase} with phrase in rails

I'd like to search and replace any occurrence of {phrase} with with phrase using rails (erb.html file). Multiple phrases will need to be substituted, and the phrases aren't known in advance.
Full Example:
Hi {guys}, I really like {ruby on rails}
Needs to become
Hi guys, ruby on rails
This is for a user-generated content site (GMT)
it's simple regexp, just use
your_string.gsub(/{(.*?)}/, '\\1')
Example:
"{aaa} is not {bbb} you know".gsub(/{(.*?)}/, '\\1')
will produce
aaa is not bbb you know
You can do this using gsub
irb(main):001:0> str = " I have written this phrase statement, I want to replace occurences of all phrase with other statement"
=> " I have written this phrase statement, I want to replace occurences of all phrase with other statement"
irb(main):002:0> str.gsub("phrase",'phrase')
=> " I have written this phrase statement, I want to replace occurences of all phrase with other statement"
A better way to do this will be to use a Markdown output engine (Redcarpet being one of the most robust)
You'd have to create a custom renderer:
#lib/custom_renderer.rb
class AutoLinks < Redcarpet::Render::HTML
def auto_link(phrase) #-> will need to search through content. Can research further
link_to phrase, "/#{phrase}"
end
end
#controller
markdown = Redcarpet::Markdown.new(AutoLinks, auto_link: "ruby on rails")
Just use a helper in your erb. For example:
tag_helper.rb:
module TagHelper
def atag(phrase)
"<a href='/#{phrase}'>#{phrase}</a>"
end
end
some.html.erb:
<%= atag('guys')%>

ActionView::Helpers::TextHelper excerpt helper is not fully functional

I am using module ActionView::Helpers::TextHelper to generate an excerpt from a text. If a word exists more than once, it will just excerpt the first occurrence.
<%= excerpt('Hello, i am a Ruby lover, a Rails lover and would never come back to PHP', 'lover', :radius => 5) %>
"...lover,..."
I was expecting the return string to be something like, becauee there two occurrences of the word 'lover':
"...lover,...lover ..."
How can i get it to work to display multiple occurrences of a keyword?
I am using rails 3.2.11.
excerpt(text, phrase, options = {}) Link:
Extracts an excerpt from text that matches the first instance of phrase. The :radius option expands the excerpt on each side of the first occurrence of phrase
as the documantation states, is only the first instance of the phrase you search, not every instance of it
I've been using a multi_excerpt() method defined in my application_helper.rb
# Returns a summary of +text+ in the form of +phrase+ excerpts
#
# multi_excerpt('This string is is a very long long long string ', 'string', radius: 5)
# # => ...This string is i...long string ...
def multi_excerpt(text, phrase, options = {})
return unless text && phrase
radius = options.fetch(:radius, 10)
omission = options.fetch(:omission, "...")
raise if phrase.is_a? Regexp
regex = /.{,#{radius}}#{Regexp.escape(phrase)}.{,#{radius}}/i
parts = text.scan(regex)
"#{omission}#{parts.join(omission)}#{omission}"
end
Linking here my related post and PR.

Regular expressions in cucumber steps

Cucumber generates out some neat webrat regex steps. I encountered a problem when I tried the this.
In feature:
And I fill in "Telephone (Home)" with "61234567"
In webrat steps:
When /^I fill in "([^\"]*)" with "([^\"]*)"$/ do |field, value|
fill_in(field, :with => value)
end
The error encountered:
Could not find field: "Telephone (Home)" (Webrat::NotFoundError)
It seems that the parenthesis between "Home" is giving problem. How do I tweak the regex to account for parenthesis?
UPDATE:
It seems that the regex wasn't the problem as the "field" instance variable did yield "Telephone (Home)". The real problem was the way webrat's "fill_in" method parses the field variable.
If you only want to capture "Telephone" try this:
/^I fill in "(\w+).*?" with "([^\"]*)"$/
If it's "Home" you're after try this:
/^I fill in "(?:.*?\()?(.+?)\)?" with "([^\"]*)"$/;
This encountered me too with the field "(log out)"...
You could call for the id field?
fill_in("user_telephone_home", :with => data)
I had a similar problem with matching labels to fields in webrat, and I came up with this code snippet which loosens the regexp used to match a label to a field. Maybe it will help you out.
I have this in my features/support/env.rb
module Webrat
module Locators
class FieldLabeledLocator < Locator
def matching_label_elements_with_numbering
label_elements.select do |label_element|
text(label_element) =~ /^.*#{Regexp.escape(#value.to_s)}.*$/i
end
end
alias_method_chain :matching_label_elements, :numbering
end
end
end
http://gist.github.com/169215

Whats the best way to put a small ruby app online?

I have a small ruby application I wrote that's an anagram searcher. It's for learning ruby, but I would like to put it up online for personal use. I have some experience with Rails, and many here have recommended Sinatra. I'm fine with either, but I cannot find any information on how to use a text file instead of a database.
The application is quite simple, validates against a text file of a word list, then finds all anagrams. I have been assuming that this should be quite simple, but I'm stuck on importing that textfile into Rails (or Sinatra if i choose that way). In the Rails project, I have placed the textfile in the lib directory.
Unfortunately, even though the path appears to be correct in Rails, I get an error:
no such file to load -- /Users/court/Sites/cvtest/lib/english.txt
(cvtest is the name of the rails project)
Here is the code. It works great by itself:
file_path = '/Users/court/Sites/anagram/dictionary/english.txt'
input_string = gets.chomp
# validate input to list
if File.foreach(file_path) {|x| break x if x.chomp == input_string}
#break down the word
word = input_string.split(//).sort
# match word
anagrams = IO.readlines(file_path).partition{
|line| line.strip!
(line.size == word.size && line.split(//).sort == word)
}[0]
#list all words except the original
anagrams.each{ |matched_word| puts matched_word unless matched_word == input_string }
#display error if
else
puts "This word cannot be found in the dictionary"
end
Factor the actual functionality (finding the anagrams) into a method. Call that method from your Web app.
In Rails, you'd create a controller action that calls that method instead of ActiveRecord. In Sinatra, you'd just create a route that calls the method. Here's a Sinatra example:
get '/word/:input'
anagrams = find_anagrams(params[:input])
anagrams.join(", ")
end
Then, when you access the http://yourapp.com/word/pool, it will print "loop, polo".
I know the question is marked as answered, but I prefer the following, as it uses query parameters rather than path based parameters, which means you can pass the parameters in using a regular GET form submission:
require 'rubygems'
require 'sinatra'
def find_anagrams word
# your anagram method here
end
get '/anagram' do
#word = params['word']
#anagrams = find_anagrams #word if #word
haml :anagram
end
And the following haml (you could use whatever template language you prefer). This will give you an input form, and show the list of anagrams if a word has been provided and an anagram list has been generated:
%h1
Enter a word
%form{:action => "anagram"}
%input{:type => "text", :name => "word"}
%input{:type => "submit"}
- if #word
%h1
Anagrams of
&= #word
- if #anagrams
%ul
- #anagrams.each do |word|
%li&= word
- else
%p No anagrams found
With sinatra, you can do anything. These examples doesn't even require sinatra, you could roll your own rack interface thing.
require 'rubygems'
require 'sinatra'
require 'yaml'
documents = YAML::load_file("your_data.yml")
Or:
require 'rubygems'
require 'sinatra'
content = Dir[File.join(__DIR__, "content/*.textile)].map {|path|
content = RedCloth(File.read(path)).to_html
}
Etcetera.

Resources