pirate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem 'activesupport'
7
+ gem 'actionpack'
8
+
9
+ gem 'searchlogic', '2.4.27'
10
+ gem 'amatch', '0.2.5'
11
+
12
+ # Add dependencies to develop your gem here.
13
+ # Include everything needed to run rake, tests, features, etc.
14
+ group :development do
15
+ gem "rspec", "~> 1.3.0"
16
+ gem "bundler", "~> 1.0.0"
17
+ gem "jeweler", "~> 1.5.2"
18
+ gem "rcov", ">= 0"
19
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,59 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionpack (3.0.3)
6
+ activemodel (= 3.0.3)
7
+ activesupport (= 3.0.3)
8
+ builder (~> 2.1.2)
9
+ erubis (~> 2.6.6)
10
+ i18n (~> 0.4)
11
+ rack (~> 1.2.1)
12
+ rack-mount (~> 0.6.13)
13
+ rack-test (~> 0.5.6)
14
+ tzinfo (~> 0.3.23)
15
+ activemodel (3.0.3)
16
+ activesupport (= 3.0.3)
17
+ builder (~> 2.1.2)
18
+ i18n (~> 0.4)
19
+ activerecord (3.0.3)
20
+ activemodel (= 3.0.3)
21
+ activesupport (= 3.0.3)
22
+ arel (~> 2.0.2)
23
+ tzinfo (~> 0.3.23)
24
+ activesupport (3.0.3)
25
+ amatch (0.2.5)
26
+ arel (2.0.6)
27
+ builder (2.1.2)
28
+ erubis (2.6.6)
29
+ abstract (>= 1.0.0)
30
+ git (1.2.5)
31
+ i18n (0.5.0)
32
+ jeweler (1.5.2)
33
+ bundler (~> 1.0.0)
34
+ git (>= 1.2.5)
35
+ rake
36
+ rack (1.2.1)
37
+ rack-mount (0.6.13)
38
+ rack (>= 1.0.0)
39
+ rack-test (0.5.6)
40
+ rack (>= 1.0)
41
+ rake (0.8.7)
42
+ rcov (0.9.9)
43
+ rspec (1.3.1)
44
+ searchlogic (2.4.27)
45
+ activerecord (>= 2.0.0)
46
+ tzinfo (0.3.23)
47
+
48
+ PLATFORMS
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ actionpack
53
+ activesupport
54
+ amatch (= 0.2.5)
55
+ bundler (~> 1.0.0)
56
+ jeweler (~> 1.5.2)
57
+ rcov
58
+ rspec (~> 1.3.0)
59
+ searchlogic (= 2.4.27)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 58Phases
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = Pirate
2
+
3
+ Custom search function for 58Phases.
4
+
5
+ == Contributing to pirate
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 58Phases. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "pirate"
16
+ gem.homepage = "http://github.com/58Phases/pirate"
17
+ gem.license = ""
18
+ gem.summary = %Q{Custom search function for 58Phases}
19
+ gem.description = %Q{Custom search function for 58Phases}
20
+ gem.email = "david@yibs.com"
21
+ gem.authors = ["David Hsu"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ gem.add_dependency 'searchlogic', '>= 2.4.27'
27
+ gem.add_dependency 'amatch', '>= 0.2.5'
28
+ end
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ #require 'rspec/core'
32
+ #require 'rspec/core/rake_task'
33
+ #RSpec::Core::RakeTask.new(:spec) do |spec|
34
+ # spec.pattern = FileList['spec/**/*_spec.rb']
35
+ #end
36
+ #
37
+ #RSpec::Core::RakeTask.new(:rcov) do |spec|
38
+ # spec.pattern = 'spec/**/*_spec.rb'
39
+ # spec.rcov = true
40
+ #end
41
+
42
+ task :default => :spec
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "pirate #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/pirate.rb ADDED
@@ -0,0 +1,163 @@
1
+ require 'action_controller'
2
+
3
+ module Pirate
4
+ # Problems:
5
+ # - named_scope is different in each app
6
+ # ex. Store.active.name_or_homepage_like, Store.not_rejected.name_like
7
+ # Should we standardize this?
8
+ # - pagination
9
+ # http://www.mail-archive.com/rubyonrails-talk@googlegroups.com/msg49775.html
10
+
11
+ mattr_accessor :result, :tag_enabled, :store_per_page, :coupon_per_page
12
+
13
+ # :redirect => 'exact' || 'partial' || 'levenshtein' || nil
14
+ @@result = { :redirect => nil, :instance => nil, :stores => nil, :coupons => nil, :tags => nil, :notice => nil }
15
+ @@tag_enabled = false
16
+
17
+ @@store_per_page = 4
18
+ @@coupon_per_page = 10
19
+
20
+ @@page = { :stores => 1, :coupons => 1 }
21
+
22
+ def self.reset_result
23
+ @@result = { :redirect => nil, :instance => nil, :stores => nil, :coupons => nil, :tags => nil, :notice => nil }
24
+ end
25
+
26
+ def self.find(search_params)
27
+ @query = search_params[:searchInput]
28
+
29
+ exact_match_redirects(@query)
30
+ levenshtein_search_stores_redirect(@query) unless @@result[:redirect]
31
+ levenshtein_search_tags_redirect(@query) if @@tag_enabled && !@@result[:redirect]
32
+
33
+ if @@result[:redirect].nil?
34
+ @@page[search_params[:cat].to_sym] = search_params[:page] if search_params[:cat] && search_params[:page]
35
+
36
+ @@result[:stores] = Store.active.remove_punct_from_name(@query.downcase).paginate(:per_page => @@store_per_page, :page => @@page[:stores])
37
+ @@result[:coupons] = Coupon.active.ordered.name_or_store_name_or_description_like(@query).paginate(:per_page => @@coupon_per_page, :page => @@page[:coupons])
38
+ @@result[:tags] = Coupon.related_tags(@query) if @@tag_enabled
39
+ end
40
+
41
+ return @@result
42
+ end
43
+
44
+ def self.exact_match_redirects(query)
45
+ reset_result
46
+
47
+ # to force a search page and avoid redirection, add ?no_redirect=true to your url
48
+ # Case Insensitive Match -- try to match store by near-exact name or domain match
49
+ foundstores = Store.active.find(:all, :conditions => [ "LOWER(name) = ? or LOWER(homepage) LIKE ?", query.downcase, "%#{query.downcase}" ] )
50
+ if !foundstores.nil? and foundstores.length == 1
51
+ @@result = { :redirect => 'exact', :instance => foundstores.first } and return
52
+ end
53
+
54
+ if @@tag_enabled
55
+ foundtags = Tag.find(:all, :conditions => [ "LOWER(name) = ?", query.downcase ] )
56
+ if !foundtags.nil? and foundtags.length == 1
57
+ @@result = { :redirect => 'exact', :instance => foundtags.first } and return
58
+ end
59
+ end
60
+
61
+ # Partial Match -- a known store name or tag name exists within the search query
62
+ foundstores = Store.active.find(:all, :conditions => [ "? LIKE CONCAT('%',LOWER(name),'%')", query.downcase ])
63
+ if !foundstores.nil? and foundstores.length == 1
64
+ @@result = { :redirect => 'partial', :instance => foundstores.first,
65
+ :notice => "We matched your search to &quot;#{foundstores.first}&quot;.  Search instead for <a href='/searches/new?searchInput=#{URI.escape(query)}&no_redirect=true'>#{query}</a>" }
66
+ return
67
+ end
68
+
69
+ # I don't think we need this, partial match in Tag is confusing users
70
+ #if @@tag_enabled
71
+ # foundtags = Tag.find(:all, :conditions => [ "? LIKE CONCAT('%',LOWER(name),'%')", query.downcase ])
72
+ # if !foundtags.nil? and foundtags.length == 1
73
+ # @@result = { :redirect => 'partial', :instance => foundtags.first,
74
+ # :notice => "We matched your search to &quot;#{foundtags.first}&quot;.  Search instead for <a href='/searches/new?searchInput=#{URI.escape(query)}&no_redirect=true'>#{query}</a>" }
75
+ # end
76
+ #end
77
+ end
78
+
79
+ def self.levenshtein_search_stores_redirect(query)
80
+ reset_result
81
+
82
+ lowquery = query.downcase.gsub(/[^\w]/, '')
83
+
84
+ foundstores = calculate_stores_by_similarity(lowquery)
85
+ foundstore = foundstores.max
86
+ if !foundstore.nil? && foundstore[0] > 0.5
87
+ store = Store.active.find(foundstore[1])
88
+ @@result = { :redirect => 'levenshtein', :instance => store,
89
+ :notice => "We matched your search to &quot;#{store.name}&quot;.  Search instead for <a href='/searches/new?searchInput=#{URI.escape(query)}&no_redirect=true'>#{query}</a>"
90
+ }
91
+ return
92
+ end
93
+
94
+ maxdist = (lowquery.length / 4).to_i
95
+ foundstores = calculate_stores_by_match(lowquery)
96
+ foundstore = foundstores.min
97
+ if !foundstore.nil? && foundstore[0] <= maxdist
98
+ store = Store.active.find(foundstore[1])
99
+ @@result = { :redirect => 'levenshtein', :instance => store,
100
+ :notice => "We matched your search to &quot;#{store.name}&quot;.  Search instead for <a href='/searches/new?searchInput=#{URI.escape(query)}&no_redirect=true'>#{query}</a>"
101
+ }
102
+ return
103
+ end
104
+ end
105
+
106
+ def self.calculate_stores_by_similarity(query)
107
+ m = Amatch::Levenshtein.new(query)
108
+
109
+ # select only names make an array of names
110
+ store_names = Store.active.all(:select => 'id, name').collect { |s| [s.id, s.name.gsub(/[^\w]/, '')] }
111
+
112
+ # array of pairs: [ levdistance, name ] take maximum
113
+ return store_names.collect { |n| [ m.similar(n[1].downcase.gsub(/[^\w]/, '')), n[0], n[1] ] }
114
+ end
115
+
116
+ def self.calculate_stores_by_match(query)
117
+ # Misspelling Match -- search term is a misspelling of the store name
118
+ # create Levenshtein matcher for our user's query, with only alphanumerics
119
+ # downcase each store name and remove non-alphanumeric characters, then match em, and pick the minimum.
120
+ m = Amatch::Levenshtein.new(query)
121
+
122
+ # select only names make an array of names
123
+ store_names = Store.active.all(:select => 'id, name').collect { |s| [s.id, s.name.gsub(/[^\w]/, '')] }
124
+
125
+ # array of pairs: [ levdistance, name ] take maximum
126
+ return store_names.collect { |n| [ m.match(n[1].downcase.gsub(/[^\w]/, '')), n[0], n[1] ] }
127
+ end
128
+
129
+ def self.levenshtein_search_tags_redirect(query)
130
+ reset_result
131
+
132
+ # Misspelling Match -- search term is a misspelling of the store name
133
+ # create Levenshtein matcher for our user's query, with only alphanumerics
134
+ # downcase each store name and remove non-alphanumeric characters, then match em, and pick the minimum.
135
+
136
+ lowquery = query.downcase.gsub(/[^\w]/, '')
137
+ m = Amatch::Levenshtein.new(lowquery)
138
+ tag_names = Tag.all(:select => 'name').collect { |t| t.name }
139
+
140
+ foundtag = tag_names.collect { |n| [ m.similar(n.downcase.gsub(/[^\w]/, '')), n ] }.max
141
+ if !foundtag.nil? && foundtag[0] > 0.5
142
+ tag = Tag.find_by_name(foundtag[1])
143
+ @@result = { :redirect => 'levenshtein', :instance => tag,
144
+ :notice => "We matched your search to &quot;#{tag.name}&quot;.  Search instead for <a href='/searches/new?searchInput=#{URI.escape(query)}&no_redirect=true'>#{query}</a>"
145
+ }
146
+ return
147
+ end
148
+
149
+ maxdist = (lowquery.length / 4).to_i
150
+ # select only names make an array of names array of pairs: [ levdistance, name ] take minimum
151
+ foundtag = tag_names.collect { |n| [ m.match(n.downcase.gsub(/[^\w]/, '')), n ] }.min
152
+ if !foundtag.nil? and foundtag[0] <= maxdist
153
+ tag = Tag.find_by_name(foundtag[1])
154
+ @@result = { :redirect => 'levenshtein', :instance => tag,
155
+ :notice => "We matched your search to &quot;#{tag.name}&quot;.  Search instead for <a href='/searches/new?searchInput=#{URI.escape(query)}&no_redirect=true'>#{query}</a>"
156
+ }
157
+ return
158
+ end
159
+ end
160
+
161
+ end
162
+
163
+ ActionController::Base.send(:include, Pirate)
@@ -0,0 +1,134 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Pirate" do
4
+ context "by 'find' method" do
5
+ it "should return matching result" do
6
+ @stores = {}
7
+ [['1', "Abe's of Maine"], ['2', "E.L.F."], ['3', "80's Purple"], ['4', "Adagio Teas"],
8
+ ['5', "Akademiks"], ['6', "Discount Contact Lenses"], ['7', "Lens.com"], ['8', "Brylane Home"],
9
+ ['9', "Directly Home"], ['10', "HomeClick"]].each do |store|
10
+ @stores[store[0]] = Factory(:approved_store, :name => store[1])
11
+ end
12
+
13
+ @tags = {}
14
+ [['1', "shoes"], ['2', "discount"], ['3', "free shipping"], ['4', "home"],
15
+ ['5', "electronics"], ['6', "promotion code"]].each do |tag|
16
+ @tags[tag[0]] = Factory(:tag, :name => tag[1])
17
+ end
18
+
19
+ Pirate.find(:searchInput => "discount", :tag_enabled => true)
20
+ Pirate.result[:redirect].should == 'exact'
21
+ Pirate.result[:instance].should == @tags['2']
22
+
23
+ Pirate.find(:searchInput => "free shipping coupon", :tag_enabled => true)
24
+ Pirate.result[:redirect].should == 'levenshtein'
25
+ Pirate.result[:instance].should == @tags['3']
26
+
27
+ Pirate.find(:searchInput => "Discount Contact", :tag_enabled => true)
28
+ Pirate.result[:redirect].should == 'levenshtein'
29
+ Pirate.result[:instance].should == @stores['6']
30
+ end
31
+ end
32
+
33
+ context 'Store' do
34
+ before :each do
35
+ @stores = {}
36
+ [['1', "Abe's of Maine"], ['2', "E.L.F."], ['3', "80's Purple"], ['4', "Adagio Teas"],
37
+ ['5', "Akademiks"], ['6', "Discount Contact Lenses"], ['7', "Lens.com"], ['8', "Brylane Home"],
38
+ ['9', "Directly Home"], ['10', "HomeClick"]].each do |store|
39
+ @stores[store[0]] = Factory(:approved_store, :name => store[1])
40
+ end
41
+ end
42
+
43
+ context "by exact_match_redirects" do
44
+ it "should redirect to the matching store" do
45
+ Pirate.exact_match_redirects("abe's of maine")
46
+ Pirate.result[:redirect].should == 'exact'
47
+ Pirate.result[:instance].should == @stores['1']
48
+
49
+ Pirate.exact_match_redirects("elf")
50
+ Pirate.result[:redirect].should == nil
51
+
52
+ Pirate.exact_match_redirects("e.l.f.")
53
+ Pirate.result[:redirect].should == 'exact'
54
+ Pirate.result[:instance].should == @stores['2']
55
+ end
56
+ end
57
+
58
+ context "by levenshtein_search_stores_redirect" do
59
+ it "should redirect to the matching store if users misspell the query" do
60
+ Pirate.levenshtein_search_stores_redirect("abe maine")
61
+ Pirate.result[:redirect].should == 'levenshtein'
62
+ Pirate.result[:instance].should == @stores['1']
63
+
64
+ Pirate.levenshtein_search_stores_redirect("elf")
65
+ Pirate.result[:redirect].should == 'levenshtein'
66
+ Pirate.result[:instance].should == @stores['2']
67
+
68
+ Pirate.levenshtein_search_stores_redirect("80s perple")
69
+ Pirate.result[:redirect].should == 'levenshtein'
70
+ Pirate.result[:instance].should == @stores['3']
71
+
72
+ Pirate.levenshtein_search_stores_redirect("adogio tee")
73
+ Pirate.result[:redirect].should == 'levenshtein'
74
+ Pirate.result[:instance].should == @stores['4']
75
+
76
+ Pirate.levenshtein_search_stores_redirect("akademic")
77
+ Pirate.result[:redirect].should == 'levenshtein'
78
+ Pirate.result[:instance].should == @stores['5']
79
+
80
+ Pirate.levenshtein_search_stores_redirect("home")
81
+ Pirate.result[:redirect].should == nil
82
+ end
83
+ end
84
+ end
85
+
86
+ context 'Tag' do
87
+ before :each do
88
+ @tags = {}
89
+ [['1', "Abe's of Maine"], ['2', "E.L.F."], ['3', "80's Purple"], ['4', "Adagio Teas"],
90
+ ['5', "Akademiks"], ['6', "Discount Contact Lenses"], ['7', "Lens.com"], ['8', "Brylane Home"],
91
+ ['9', "Directly Home"], ['10', "HomeClick"]].each do |tag|
92
+ @tags[tag[0]] = Factory(:tag, :name => tag[1])
93
+ end
94
+ end
95
+
96
+ context "by exact_match_redirects" do
97
+ it "should redirect to the matching tag" do
98
+ Pirate.tag_enabled = true
99
+ Pirate.exact_match_redirects("abe's of maine")
100
+ Pirate.result[:redirect].should == 'exact'
101
+ Pirate.result[:instance].should == @tags['1']
102
+
103
+ Pirate.exact_match_redirects("elf")
104
+ Pirate.result[:redirect].should == nil
105
+
106
+ Pirate.exact_match_redirects("e.l.f.")
107
+ Pirate.result[:redirect].should == 'exact'
108
+ Pirate.result[:instance].should == @tags['2']
109
+ end
110
+ end
111
+
112
+ context "by levenshtein_search_tags_redirect" do
113
+ it "should redirect to the matching tag" do
114
+ Pirate.levenshtein_search_tags_redirect("abe's of maine")
115
+ Pirate.result[:redirect].should == 'levenshtein'
116
+ Pirate.result[:instance].should == @tags['1']
117
+
118
+ Pirate.levenshtein_search_tags_redirect("elf")
119
+ Pirate.result[:redirect].should == 'levenshtein'
120
+ Pirate.result[:instance].should == @tags['2']
121
+
122
+ Pirate.levenshtein_search_tags_redirect("e.l.f.")
123
+ Pirate.result[:redirect].should == 'levenshtein'
124
+ Pirate.result[:instance].should == @tags['2']
125
+
126
+ Pirate.levenshtein_search_tags_redirect("80s Perple")
127
+ Pirate.result[:redirect].should == 'levenshtein'
128
+ Pirate.result[:instance].should == @tags['3']
129
+ end
130
+ end
131
+ end
132
+
133
+ end
134
+
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'pirate'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,232 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pirate
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - David Hsu
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-20 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ type: :runtime
23
+ prerelease: false
24
+ name: activesupport
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ requirement: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ type: :runtime
37
+ prerelease: false
38
+ name: actionpack
39
+ version_requirements: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ requirement: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ type: :runtime
51
+ prerelease: false
52
+ name: searchlogic
53
+ version_requirements: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - "="
57
+ - !ruby/object:Gem::Version
58
+ hash: 41
59
+ segments:
60
+ - 2
61
+ - 4
62
+ - 27
63
+ version: 2.4.27
64
+ requirement: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ type: :runtime
67
+ prerelease: false
68
+ name: amatch
69
+ version_requirements: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - "="
73
+ - !ruby/object:Gem::Version
74
+ hash: 29
75
+ segments:
76
+ - 0
77
+ - 2
78
+ - 5
79
+ version: 0.2.5
80
+ requirement: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ type: :development
83
+ prerelease: false
84
+ name: rspec
85
+ version_requirements: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ hash: 27
91
+ segments:
92
+ - 1
93
+ - 3
94
+ - 0
95
+ version: 1.3.0
96
+ requirement: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ type: :development
99
+ prerelease: false
100
+ name: bundler
101
+ version_requirements: &id006 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ~>
105
+ - !ruby/object:Gem::Version
106
+ hash: 23
107
+ segments:
108
+ - 1
109
+ - 0
110
+ - 0
111
+ version: 1.0.0
112
+ requirement: *id006
113
+ - !ruby/object:Gem::Dependency
114
+ type: :development
115
+ prerelease: false
116
+ name: jeweler
117
+ version_requirements: &id007 !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ~>
121
+ - !ruby/object:Gem::Version
122
+ hash: 7
123
+ segments:
124
+ - 1
125
+ - 5
126
+ - 2
127
+ version: 1.5.2
128
+ requirement: *id007
129
+ - !ruby/object:Gem::Dependency
130
+ type: :development
131
+ prerelease: false
132
+ name: rcov
133
+ version_requirements: &id008 !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ hash: 3
139
+ segments:
140
+ - 0
141
+ version: "0"
142
+ requirement: *id008
143
+ - !ruby/object:Gem::Dependency
144
+ type: :runtime
145
+ prerelease: false
146
+ name: searchlogic
147
+ version_requirements: &id009 !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ hash: 41
153
+ segments:
154
+ - 2
155
+ - 4
156
+ - 27
157
+ version: 2.4.27
158
+ requirement: *id009
159
+ - !ruby/object:Gem::Dependency
160
+ type: :runtime
161
+ prerelease: false
162
+ name: amatch
163
+ version_requirements: &id010 !ruby/object:Gem::Requirement
164
+ none: false
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ hash: 29
169
+ segments:
170
+ - 0
171
+ - 2
172
+ - 5
173
+ version: 0.2.5
174
+ requirement: *id010
175
+ description: Custom search function for 58Phases
176
+ email: david@yibs.com
177
+ executables: []
178
+
179
+ extensions: []
180
+
181
+ extra_rdoc_files:
182
+ - LICENSE.txt
183
+ - README.rdoc
184
+ files:
185
+ - .document
186
+ - .rspec
187
+ - Gemfile
188
+ - Gemfile.lock
189
+ - LICENSE.txt
190
+ - README.rdoc
191
+ - Rakefile
192
+ - VERSION
193
+ - lib/pirate.rb
194
+ - spec/pirate_spec.rb
195
+ - spec/spec_helper.rb
196
+ has_rdoc: true
197
+ homepage: http://github.com/58Phases/pirate
198
+ licenses:
199
+ - ""
200
+ post_install_message:
201
+ rdoc_options: []
202
+
203
+ require_paths:
204
+ - lib
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ none: false
207
+ requirements:
208
+ - - ">="
209
+ - !ruby/object:Gem::Version
210
+ hash: 3
211
+ segments:
212
+ - 0
213
+ version: "0"
214
+ required_rubygems_version: !ruby/object:Gem::Requirement
215
+ none: false
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ hash: 3
220
+ segments:
221
+ - 0
222
+ version: "0"
223
+ requirements: []
224
+
225
+ rubyforge_project:
226
+ rubygems_version: 1.3.7
227
+ signing_key:
228
+ specification_version: 3
229
+ summary: Custom search function for 58Phases
230
+ test_files:
231
+ - spec/pirate_spec.rb
232
+ - spec/spec_helper.rb