solutious-stella 0.6.0 → 0.7.0.001
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +3 -15
- data/LICENSE.txt +1 -1
- data/README.rdoc +90 -60
- data/Rakefile +32 -42
- data/bin/stella +138 -0
- data/examples/basic/listing_ids.csv +7 -0
- data/examples/basic/plan.rb +71 -0
- data/lib/stella.rb +57 -104
- data/lib/stella/cli.rb +66 -0
- data/lib/stella/client.rb +197 -0
- data/lib/stella/config.rb +87 -0
- data/lib/stella/data.rb +85 -0
- data/lib/stella/data/http.rb +2 -257
- data/lib/stella/data/http/body.rb +15 -0
- data/lib/stella/data/http/request.rb +116 -0
- data/lib/stella/data/http/response.rb +92 -0
- data/lib/stella/dsl.rb +5 -0
- data/lib/stella/engine.rb +55 -0
- data/lib/stella/engine/functional.rb +39 -0
- data/lib/stella/engine/load.rb +106 -0
- data/lib/stella/exceptions.rb +15 -0
- data/lib/stella/guidelines.rb +18 -0
- data/lib/stella/mixins.rb +2 -0
- data/lib/stella/stats.rb +3 -7
- data/lib/stella/testplan.rb +95 -220
- data/lib/stella/testplan/stats.rb +26 -0
- data/lib/stella/testplan/usecase.rb +67 -0
- data/lib/stella/utils.rb +126 -0
- data/lib/{util → stella/utils}/httputil.rb +0 -0
- data/lib/stella/version.rb +15 -0
- data/lib/threadify.rb +0 -6
- data/stella.gemspec +43 -49
- data/support/example_webapp.rb +246 -0
- data/support/useragents.txt +75 -0
- metadata +66 -31
- data/bin/example_test.rb +0 -82
- data/bin/example_webapp.rb +0 -63
- data/lib/logger.rb +0 -79
- data/lib/stella/clients.rb +0 -161
- data/lib/stella/command/base.rb +0 -20
- data/lib/stella/command/form.rb +0 -36
- data/lib/stella/command/get.rb +0 -44
- data/lib/stella/common.rb +0 -53
- data/lib/stella/crypto.rb +0 -88
- data/lib/stella/data/domain.rb +0 -82
- data/lib/stella/environment.rb +0 -66
- data/lib/stella/functest.rb +0 -105
- data/lib/stella/loadtest.rb +0 -186
- data/lib/stella/testrunner.rb +0 -64
- data/lib/storable.rb +0 -280
- data/lib/timeunits.rb +0 -65
- data/tryouts/drb/drb_test.rb +0 -65
- data/tryouts/drb/open4.rb +0 -19
- data/tryouts/drb/slave.rb +0 -27
- data/tryouts/oo_tryout.rb +0 -30
data/lib/stella/utils.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
|
2
|
+
require 'socket'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
require 'timeout'
|
7
|
+
|
8
|
+
module Stella
|
9
|
+
|
10
|
+
# A motley collection of methods that Stella loves to call!
|
11
|
+
module Utils
|
12
|
+
extend self
|
13
|
+
include Socket::Constants
|
14
|
+
|
15
|
+
# Return the external IP address (the one seen by the internet)
|
16
|
+
def external_ip_address
|
17
|
+
ip = nil
|
18
|
+
begin
|
19
|
+
%w{solutious.heroku.com/ip}.each do |sponge|
|
20
|
+
ipstr = Net::HTTP.get(URI.parse("http://#{sponge}")) || ''
|
21
|
+
ip = /([0-9]{1,3}\.){3}[0-9]{1,3}/.match(ipstr).to_s
|
22
|
+
break if ip && !ip.empty?
|
23
|
+
end
|
24
|
+
rescue SocketError, Errno::ETIMEDOUT => ex
|
25
|
+
Stella.le "Connection Error. Check your internets!"
|
26
|
+
end
|
27
|
+
ip
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return the local IP address which receives external traffic
|
31
|
+
# from: http://coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/
|
32
|
+
# NOTE: This <em>does not</em> open a connection to the IP address.
|
33
|
+
def internal_ip_address
|
34
|
+
# turn off reverse DNS resolution temporarily
|
35
|
+
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
|
36
|
+
ip = UDPSocket.open {|s| s.connect('75.101.137.7', 1); s.addr.last } # Solutious IP
|
37
|
+
ip
|
38
|
+
ensure
|
39
|
+
Socket.do_not_reverse_lookup = orig
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
# <tt>require</tt> a glob of files.
|
44
|
+
# * +path+ is a list of path elements which is sent to File.join
|
45
|
+
# and then to Dir.glob. The list of files found are sent to require.
|
46
|
+
# Nothing is returned but LoadError exceptions are caught. The message
|
47
|
+
# is printed to STDERR and the program exits with 7.
|
48
|
+
def require_glob(*path)
|
49
|
+
begin
|
50
|
+
Dir.glob(File.join(*path.flatten)).each do |path|
|
51
|
+
require path
|
52
|
+
end
|
53
|
+
rescue LoadError => ex
|
54
|
+
puts "Error: #{ex.message}"
|
55
|
+
exit 7
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Checks whether something is listening to a socket.
|
60
|
+
# * +host+ A hostname
|
61
|
+
# * +port+ The port to check
|
62
|
+
# * +wait+ The number of seconds to wait for before timing out.
|
63
|
+
#
|
64
|
+
# Returns true if +host+ allows a socket connection on +port+.
|
65
|
+
# Returns false if one of the following exceptions is raised:
|
66
|
+
# Errno::EAFNOSUPPORT, Errno::ECONNREFUSED, SocketError, Timeout::Error
|
67
|
+
#
|
68
|
+
def service_available?(host, port, wait=3)
|
69
|
+
if Stella.sysinfo.vm == :java
|
70
|
+
begin
|
71
|
+
iadd = Java::InetSocketAddress.new host, port
|
72
|
+
socket = Java::Socket.new
|
73
|
+
socket.connect iadd, wait * 1000 # milliseconds
|
74
|
+
success = !socket.isClosed && socket.isConnected
|
75
|
+
rescue NativeException => ex
|
76
|
+
puts ex.message, ex.backtrace if Stella.debug?
|
77
|
+
false
|
78
|
+
end
|
79
|
+
else
|
80
|
+
begin
|
81
|
+
status = Timeout::timeout(wait) do
|
82
|
+
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
|
83
|
+
sockaddr = Socket.pack_sockaddr_in( port, host )
|
84
|
+
socket.connect( sockaddr )
|
85
|
+
end
|
86
|
+
true
|
87
|
+
rescue Errno::EAFNOSUPPORT, Errno::ECONNREFUSED, SocketError, Timeout::Error => ex
|
88
|
+
puts ex.class, ex.message, ex.backtrace if Stella.debug?
|
89
|
+
false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# A basic file writer
|
95
|
+
def write_to_file(filename, content, mode, chmod=600)
|
96
|
+
mode = (mode == :append) ? 'a' : 'w'
|
97
|
+
f = File.open(filename,mode)
|
98
|
+
f.puts content
|
99
|
+
f.close
|
100
|
+
return unless Stella.sysinfo.os == :unix
|
101
|
+
raise "Provided chmod is not a Fixnum (#{chmod})" unless chmod.is_a?(Fixnum)
|
102
|
+
File.chmod(chmod, filename)
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Generates a string of random alphanumeric characters.
|
107
|
+
# * +len+ is the length, an Integer. Default: 8
|
108
|
+
# * +safe+ in safe-mode, ambiguous characters are removed (default: true):
|
109
|
+
# i l o 1 0
|
110
|
+
def strand( len=8, safe=true )
|
111
|
+
chars = ("a".."z").to_a + ("0".."9").to_a
|
112
|
+
chars.delete_if { |v| %w(i l o 1 0).member?(v) } if safe
|
113
|
+
str = ""
|
114
|
+
1.upto(len) { |i| str << chars[rand(chars.size-1)] }
|
115
|
+
str
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns +str+ with the leading indentation removed.
|
119
|
+
# Stolen from http://github.com/mynyml/unindent/ because it was better.
|
120
|
+
def noindent(str)
|
121
|
+
indent = str.split($/).each {|line| !line.strip.empty? }.map {|line| line.index(/[^\s]/) }.compact.min
|
122
|
+
str.gsub(/^[[:blank:]]{#{indent}}/, '')
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Stella
|
4
|
+
module Version
|
5
|
+
unless defined?(MAJOR)
|
6
|
+
MAJOR = 0.freeze
|
7
|
+
MINOR = 7.freeze
|
8
|
+
TINY = 0.freeze
|
9
|
+
PATCH = '001'.freeze
|
10
|
+
end
|
11
|
+
def self.to_s; [MAJOR, MINOR, TINY].join('.'); end
|
12
|
+
def self.to_f; self.to_s.to_f; end
|
13
|
+
def self.patch; PATCH; end
|
14
|
+
end
|
15
|
+
end
|
data/lib/threadify.rb
CHANGED
data/stella.gemspec
CHANGED
@@ -1,69 +1,63 @@
|
|
1
1
|
@spec = Gem::Specification.new do |s|
|
2
|
-
|
3
|
-
s.rubyforge_project =
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
s.name = "stella"
|
3
|
+
s.rubyforge_project = 'stella'
|
4
|
+
s.version = "0.7.0.001"
|
5
|
+
s.summary = "Stella: Your friend in performance testing."
|
6
|
+
s.description = s.summary
|
7
|
+
s.author = "Delano Mandelbaum"
|
8
|
+
s.email = "delano@solutious.com"
|
9
|
+
s.homepage = "http://solutious.com/projects/stella/"
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
s.
|
11
|
+
s.extra_rdoc_files = %w[README.rdoc LICENSE.txt CHANGES.txt]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.rdoc_options = ["--line-numbers", "--title", s.summary, "--main", "README.rdoc"]
|
14
|
+
s.require_paths = %w[lib]
|
14
15
|
|
16
|
+
s.executables = %w[stella]
|
17
|
+
|
18
|
+
s.add_dependency 'drydock', '>= 0.6.7'
|
19
|
+
s.add_dependency 'gibbler', '>= 0.6.2'
|
20
|
+
s.add_dependency 'storable', '>= 0.5.7'
|
21
|
+
s.add_dependency 'httpclient', '>= 2.1.5'
|
15
22
|
|
16
23
|
# = MANIFEST =
|
17
|
-
# The complete list of files to be included in the release. When GitHub packages your gem,
|
18
|
-
# it doesn't allow you to run any command that accesses the filesystem. You will get an
|
19
|
-
# error. You can ask your VCS for the list of versioned files:
|
20
24
|
# git ls-files
|
21
|
-
# svn list -R
|
22
25
|
s.files = %w(
|
23
26
|
CHANGES.txt
|
24
27
|
LICENSE.txt
|
25
28
|
README.rdoc
|
26
29
|
Rakefile
|
27
|
-
bin/
|
28
|
-
|
29
|
-
|
30
|
+
bin/stella
|
31
|
+
examples/basic/listing_ids.csv
|
32
|
+
examples/basic/plan.rb
|
30
33
|
lib/stella.rb
|
31
|
-
lib/stella/
|
32
|
-
lib/stella/
|
33
|
-
lib/stella/
|
34
|
-
lib/stella/
|
35
|
-
lib/stella/common.rb
|
36
|
-
lib/stella/crypto.rb
|
37
|
-
lib/stella/data/domain.rb
|
34
|
+
lib/stella/cli.rb
|
35
|
+
lib/stella/client.rb
|
36
|
+
lib/stella/config.rb
|
37
|
+
lib/stella/data.rb
|
38
38
|
lib/stella/data/http.rb
|
39
|
-
lib/stella/
|
40
|
-
lib/stella/
|
41
|
-
lib/stella/
|
39
|
+
lib/stella/data/http/body.rb
|
40
|
+
lib/stella/data/http/request.rb
|
41
|
+
lib/stella/data/http/response.rb
|
42
|
+
lib/stella/dsl.rb
|
43
|
+
lib/stella/engine.rb
|
44
|
+
lib/stella/engine/functional.rb
|
45
|
+
lib/stella/engine/load.rb
|
46
|
+
lib/stella/exceptions.rb
|
47
|
+
lib/stella/guidelines.rb
|
48
|
+
lib/stella/mixins.rb
|
42
49
|
lib/stella/stats.rb
|
43
50
|
lib/stella/testplan.rb
|
44
|
-
lib/stella/
|
45
|
-
lib/
|
51
|
+
lib/stella/testplan/stats.rb
|
52
|
+
lib/stella/testplan/usecase.rb
|
53
|
+
lib/stella/utils.rb
|
54
|
+
lib/stella/utils/httputil.rb
|
55
|
+
lib/stella/version.rb
|
46
56
|
lib/threadify.rb
|
47
|
-
lib/timeunits.rb
|
48
|
-
lib/util/httputil.rb
|
49
57
|
stella.gemspec
|
50
|
-
|
51
|
-
|
52
|
-
tryouts/drb/slave.rb
|
53
|
-
tryouts/oo_tryout.rb
|
58
|
+
support/example_webapp.rb
|
59
|
+
support/useragents.txt
|
54
60
|
)
|
55
|
-
|
56
|
-
# = EXECUTABLES =
|
57
|
-
# The list of executables in your project (if any). Don't include the path,
|
58
|
-
# just the base filename.
|
59
|
-
s.executables = %w[]
|
60
|
-
|
61
|
-
s.extra_rdoc_files = %w[README.rdoc LICENSE.txt]
|
62
|
-
s.rdoc_options = ["--line-numbers", "--title", s.summary, "--main", "README.rdoc"]
|
63
|
-
|
64
|
-
s.has_rdoc = true
|
65
|
-
s.require_paths = %w[lib]
|
66
|
-
s.rubygems_version = '1.1.1'
|
67
61
|
|
68
62
|
|
69
|
-
end
|
63
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Use Ruby 1.8
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
require "rack"
|
7
|
+
require "sinatra"
|
8
|
+
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
set :run => true
|
12
|
+
set :environment => :development
|
13
|
+
set :dump_errors => true
|
14
|
+
set :port => 3114
|
15
|
+
set :reload => true
|
16
|
+
set :max_listings => 1000
|
17
|
+
|
18
|
+
#log = File.new("/dev/null", "a")
|
19
|
+
#STDOUT.reopen(log)
|
20
|
+
#STDERR.reopen(log)
|
21
|
+
|
22
|
+
#use Rack::Auth::Basic do |username, password|
|
23
|
+
# username == 'stella' && password == 'stella'
|
24
|
+
#end
|
25
|
+
|
26
|
+
before do
|
27
|
+
@title = "Business Finder"
|
28
|
+
end
|
29
|
+
|
30
|
+
get '/' do
|
31
|
+
@title << " - Search"
|
32
|
+
erb :search_form
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
get '/search/?' do
|
37
|
+
redirect '/' if blank?(params[:what]) && blank?(params[:where])
|
38
|
+
params[:what] ||= ''
|
39
|
+
params[:where] ||= ''
|
40
|
+
@title << " - Search Results"
|
41
|
+
@listings = filter_name(params[:what], options.listings)
|
42
|
+
if !blank?(params[:where])
|
43
|
+
@listings = filter_city(params[:where], @listings)
|
44
|
+
end
|
45
|
+
if @listings.empty?
|
46
|
+
status 404
|
47
|
+
erb :search_error
|
48
|
+
else
|
49
|
+
erb :search_results
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
get '/listing/add' do
|
54
|
+
erb :add_form
|
55
|
+
end
|
56
|
+
|
57
|
+
post '/listing/add' do
|
58
|
+
@title = "Add a Business"
|
59
|
+
if blank?(params[:name]) || blank?(params[:city])
|
60
|
+
status 500
|
61
|
+
@msg = blank?(params[:city]) ? "Must specify city" : "Must specify name"
|
62
|
+
erb :add_form
|
63
|
+
else
|
64
|
+
@listings = options.listings
|
65
|
+
if find_name(params[:name], @listings).empty?
|
66
|
+
@listings.shift if @listings.size >= options.max_listings
|
67
|
+
@listings << { :name => params[:name], :id => rand(100000), :city => params[:city] }
|
68
|
+
redirect '/listings'
|
69
|
+
else
|
70
|
+
status 500
|
71
|
+
@msg = "That business exists (#{params[:name]})"
|
72
|
+
erb :add_form
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
get '/listing/:id.yaml' do
|
78
|
+
content_type "text/yaml"
|
79
|
+
listing = filter_id params[:id], options.listings
|
80
|
+
listing.to_yaml
|
81
|
+
end
|
82
|
+
|
83
|
+
get '/listing/:id' do
|
84
|
+
@listings = filter_id(params[:id], options.listings)
|
85
|
+
redirect '/' if @listings.empty?
|
86
|
+
@title = "Business Listing - #{@listings.first[:name]}"
|
87
|
+
erb :listings
|
88
|
+
end
|
89
|
+
|
90
|
+
get '/listings' do
|
91
|
+
@listings = options.listings
|
92
|
+
@title = "Business Listings"
|
93
|
+
erb :listings
|
94
|
+
end
|
95
|
+
|
96
|
+
get '/listings.yaml' do
|
97
|
+
content_type "text/yaml"
|
98
|
+
@listings = options.listings
|
99
|
+
@title = "Business Listings"
|
100
|
+
@listings.to_yaml
|
101
|
+
end
|
102
|
+
|
103
|
+
set :listings => [
|
104
|
+
{ :id => 1000, :name => 'John West Smoked Oysters', :city => 'Toronto' },
|
105
|
+
{ :id => 1001, :name => 'Fire Town Lightning Rods', :city => 'Toronto' },
|
106
|
+
{ :id => 1002, :name => 'Oversized Pen and Ink Co', :city => 'Toronto' },
|
107
|
+
{ :id => 1003, :name => 'The Rathzenburg Brothers', :city => 'Toronto' },
|
108
|
+
{ :id => 1004, :name => 'Forever and Always Beads', :city => 'Montreal' },
|
109
|
+
{ :id => 1005, :name => "Big Al's Flavour Country", :city => 'Montreal' },
|
110
|
+
{ :id => 1006, :name => 'Big Time Furniture World', :city => 'Montreal' },
|
111
|
+
{ :id => 1007, :name => 'High-End Keyboard Makers', :city => 'Montreal' }
|
112
|
+
]
|
113
|
+
|
114
|
+
before do
|
115
|
+
@cookie = request.cookies["bff-history"]
|
116
|
+
@cookie = blank?(@cookie) ? {} : YAML.load(@cookie)
|
117
|
+
@cookie[:history] ||= []
|
118
|
+
if params[:clear] == 'true'
|
119
|
+
@cookie[:history] = []
|
120
|
+
@cookie[:location] = ''
|
121
|
+
end
|
122
|
+
@cookie[:history].delete params[:what]
|
123
|
+
@cookie[:history].unshift params[:what] unless blank?(params[:what])
|
124
|
+
@cookie[:history].pop if @cookie[:history].size > 5
|
125
|
+
@cookie[:location] = params[:where] unless blank?(params[:where])
|
126
|
+
response.set_cookie "bff-history", :path => '/', :value => @cookie.to_yaml
|
127
|
+
end
|
128
|
+
|
129
|
+
helpers do
|
130
|
+
|
131
|
+
def blank?(v)
|
132
|
+
v.nil? || v.empty?
|
133
|
+
end
|
134
|
+
|
135
|
+
def filter_id(id, listings)
|
136
|
+
listings.select { |l| l[:id] == id.to_i }
|
137
|
+
end
|
138
|
+
|
139
|
+
def filter_name(name, listings)
|
140
|
+
listings.select { |l| l[:name].match(/#{name}/i) }
|
141
|
+
end
|
142
|
+
|
143
|
+
def find_name(name, listings)
|
144
|
+
listings.select { |l| l[:name] == name }
|
145
|
+
end
|
146
|
+
|
147
|
+
def filter_city(city, listings)
|
148
|
+
listings.select { |l| l[:city].match(/#{city}/i) }
|
149
|
+
end
|
150
|
+
|
151
|
+
def format_listing(lid, name, city)
|
152
|
+
listing = %Q{<div class="listing" id="listing-#{lid}">}
|
153
|
+
listing << %Q{<a href="/listing/#{lid}.yaml">#{name}</a> }
|
154
|
+
listing << %Q{#{city}</div>}
|
155
|
+
end
|
156
|
+
|
157
|
+
# Generates a string of random alphanumeric characters
|
158
|
+
# These are used as IDs throughout the system
|
159
|
+
def strand( len )
|
160
|
+
chars = ("a".."z").to_a + ("0".."9").to_a
|
161
|
+
newpass = ""
|
162
|
+
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
|
163
|
+
return newpass
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
__END__
|
169
|
+
|
170
|
+
@@layout
|
171
|
+
<html>
|
172
|
+
<head>
|
173
|
+
<title><%= @title %></title>
|
174
|
+
<style>
|
175
|
+
.hilite { background-color: #FEE00B; font-weight: bold; }
|
176
|
+
.footer { color: #ccc; font-weight: lighter; font-size: 80%; margin-top: 30px; }
|
177
|
+
.footer a { color: #69c;}
|
178
|
+
</style>
|
179
|
+
</head>
|
180
|
+
<body>
|
181
|
+
<h1>Business Finder</h1>
|
182
|
+
<p style="margin-left: 50px; margin-top: 20px;"><em>
|
183
|
+
<a href="/">New Search</a> -
|
184
|
+
<a href="/listing/add?name=<%= params[:what] %>&city=<%= params[:where] %>">Add Listing</a> -
|
185
|
+
<a href="/?clear=true">!!</a> -
|
186
|
+
<a href="/listings">View All</a>
|
187
|
+
</em></p>
|
188
|
+
<%= yield %>
|
189
|
+
<div class="footer">
|
190
|
+
A <a href="http://solutious.com/projects/stella/">Stella</a> demo by <a href="http://solutious.com/">Solutious</a>.
|
191
|
+
</div>
|
192
|
+
</body>
|
193
|
+
</html>
|
194
|
+
|
195
|
+
@@add_form
|
196
|
+
<% city = blank?(params[:city]) ? 'Toronto' : params[:city] %>
|
197
|
+
<% if !blank?(@msg) %>
|
198
|
+
<p style="color: red"><em>Error: <%= @msg %></em></p>
|
199
|
+
<% end %>
|
200
|
+
<form method="post">
|
201
|
+
Name: <input name="name" value="<%= params[:name] %>"/><br/>
|
202
|
+
City: <input name="city" value="<%= city %>" /><br/>
|
203
|
+
<input type="submit" />
|
204
|
+
</form>
|
205
|
+
|
206
|
+
@@listings
|
207
|
+
<% for l in @listings %>
|
208
|
+
<%= format_listing(l[:id], l[:name], l[:city]) %>
|
209
|
+
<% end %>
|
210
|
+
|
211
|
+
@@search_form
|
212
|
+
<form action="/search">
|
213
|
+
What: <input name="what" value="" /><br/>
|
214
|
+
Where: <input name="where" value="<%= @cookie[:location] %>" /><br/>
|
215
|
+
<input type="submit" />
|
216
|
+
</form>
|
217
|
+
<ul id="history">
|
218
|
+
<% unless @cookie[:history].empty? %>
|
219
|
+
<h3>Previous Searches</h3>
|
220
|
+
<% end %>
|
221
|
+
<% for what in @cookie[:history] %>
|
222
|
+
<li><em><a href="/search/?what=<%= what %>&where=<%= @cookie[:location] %>"><%= what %></a></em></li>
|
223
|
+
<% end %>
|
224
|
+
</ul>
|
225
|
+
|
226
|
+
@@search_results
|
227
|
+
Looking
|
228
|
+
<% if !blank?(params[:what]) %>
|
229
|
+
for "<b><%= params[:what] %></b>"
|
230
|
+
<% end %>
|
231
|
+
<% if !blank?(params[:where]) %>
|
232
|
+
in "<b><%= params[:where] %></b>"
|
233
|
+
<% end %>
|
234
|
+
<br/><br/>
|
235
|
+
<% for l in @listings %>
|
236
|
+
<% name = l[:name].gsub(/(#{params[:what]})/i, "<span class='hilite'>\\1</span>") %>
|
237
|
+
<% city = l[:city].gsub(/(#{params[:where]})/i, "<span class='hilite'>\\1</span>") %>
|
238
|
+
<%= format_listing(l[:id], name, city) %>
|
239
|
+
<% end %>
|
240
|
+
|
241
|
+
@@search_error
|
242
|
+
Looking for "<b><%= params[:what] %></b>"
|
243
|
+
<% if !blank?(params[:where]) %>
|
244
|
+
in "<b><%= params[:where] %></b>"
|
245
|
+
<% end %>
|
246
|
+
<p><i>Nothing found</i></p>
|