has_searcher 0.0.17 → 0.0.90

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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
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,3 @@
1
+ = HasSearcher
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile CHANGED
@@ -1,2 +1,28 @@
1
- require 'bundler'
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'HasSearcher'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
2
27
  Bundler::GemHelper.install_tasks
28
+
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,4 @@
1
+ module HasSearcher
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module HasSearcher
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -1,23 +1,24 @@
1
- class Boostificator
1
+ class Searcher::Boostificator
2
2
  MILLIS_IN_YEAR = 1000 * 60 * 60 * 24 * 365
3
3
  PRECISION = 6
4
4
 
5
- attr_accessor :search, :field
5
+ attr_accessor :boost_field
6
6
 
7
7
  attr_accessor :m, :x, :a, :b
8
8
 
9
9
  attr_accessor :extra_boost
10
10
 
11
- def initialize(options={})
11
+ def initialize(boost_field, options={})
12
+ self.boost_field = boost_field
12
13
  options.reverse_merge!(:a => 1.0, :b => 1.0, :m => 1.0 / MILLIS_IN_YEAR, :extra_boost => 1.0)
13
- options.each do |field, value|
14
- self.send("#{field}=", value)
14
+ options.each do |attribute, value|
15
+ self.send("#{attribute}=", value)
15
16
  end
16
17
  end
17
18
 
18
19
 
19
- def adjust_solr_params
20
- search.adjust_solr_params do |params|
20
+ def adjust_solr_params(sunspot)
21
+ sunspot.adjust_solr_params do |params|
21
22
  params[:boost] = "product(#{extra_boost},#{recip_s})"
22
23
  params[:defType] = 'edismax'
23
24
  end
@@ -25,7 +26,7 @@ class Boostificator
25
26
 
26
27
  private
27
28
  def recip_s
28
- @recip_s ||= "map(recip(abs(ms(#{now_s},#{field})),#{m},#{a},#{b}),#{recip_min},#{recip_max},1)"
29
+ @recip_s ||= "map(recip(abs(ms(#{now_s},#{boost_field})),#{m},#{a},#{b}),#{recip_min},#{recip_max},1)"
29
30
  end
30
31
 
31
32
  def now
@@ -51,5 +52,4 @@ class Boostificator
51
52
  def recip_max
52
53
  @recip_max ||= sprintf("%f", (recip * 10**PRECISION).ceil/10.0**PRECISION)
53
54
  end
54
-
55
55
  end
@@ -0,0 +1,76 @@
1
+ class Searcher::Configuration
2
+ attr_accessor :searcher, :scopes
3
+
4
+ attr_accessor :facets
5
+
6
+ attr_writer :models
7
+
8
+ delegate :search_object, :to => :searcher
9
+
10
+ def initialize(searcher, &block)
11
+ self.searcher = searcher
12
+ self.scopes = {}
13
+ self.facets = {}
14
+ self.models = []
15
+ scope :runtime
16
+ scope :default
17
+ instance_eval &block if block
18
+ end
19
+
20
+ def keywords(field, options={})
21
+ search_object.create_field(field, options)
22
+ scope do |sunspot|
23
+ sunspot.fulltext search_object.send(field) if search_object.send(field).presence
24
+ end
25
+ end
26
+
27
+ def models(*names_or_clases)
28
+ self.models = [*names_or_clases]
29
+ end
30
+
31
+ def search_models
32
+ @search_models ||= @models.map do |name_or_class|
33
+ name_or_class.is_a?(Class) ? name_or_class : name_or_class.to_s.classify.constantize
34
+ end
35
+ end
36
+
37
+ def property(field, options={}, &block)
38
+ modificators = [*options[:modificator]] + [*options[:modificators]]
39
+
40
+ modificators.each do |modificator|
41
+
42
+ request_field = [field, modificator].compact.join('_')
43
+
44
+ search_object.create_field(request_field, options)
45
+
46
+ if block
47
+ scope &block
48
+ else
49
+ scope do |sunspot|
50
+ sunspot.with(field).send(modificator, search_object.send(request_field)) if search_object.send(request_field).presence
51
+ end
52
+ end
53
+ end
54
+
55
+ if modificators.empty?
56
+ search_object.create_field(field, options)
57
+ if block
58
+ scope &block
59
+ else
60
+ scope do |sunspot|
61
+ sunspot.with(field, search_object.send(field)) if search_object.send(field).presence
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ def facet(name, &block)
68
+ facets[name] = block
69
+ end
70
+
71
+ def scope(name=:default, &block)
72
+ scopes[name] ||= []
73
+ scopes[name] << block if block
74
+ searcher
75
+ end
76
+ end
@@ -0,0 +1,28 @@
1
+ class Searcher::Model
2
+ attr_accessor :methods, :searcher
3
+
4
+ def initialize(searcher)
5
+ self.searcher = searcher
6
+ self.methods = Module.new
7
+ self.extend self.methods
8
+ end
9
+
10
+ def attributes=(params=nil)
11
+ params ||= {}
12
+ params.each do |field, value|
13
+ self.send "#{field}=", value if respond_to? "#{field}="
14
+ end
15
+ end
16
+
17
+ def create_field(name, options)
18
+ methods.class_eval do
19
+ define_method name do
20
+ instance_variable_get("@#{name}") ||
21
+ (options[:default].call if options[:default] && options[:default].respond_to?(:call))
22
+ end
23
+ define_method "#{name}=" do |value|
24
+ instance_variable_set("@#{name}", value)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,114 @@
1
+ class Searcher
2
+
3
+ attr_accessor :configuration, :sunspot, :search_object
4
+ attr_accessor :scope_chain
5
+
6
+ delegate :current_page, :num_pages, :limit_value, :to => :results
7
+
8
+ def initialize(&block)
9
+ self.scope_chain = [:default, :runtime]
10
+ self.search_object = Searcher::Model.new(self)
11
+ self.configuration = Configuration.new(self, &block)
12
+ end
13
+
14
+ def sunspot
15
+ @sunspot ||= Sunspot.new_search configuration.search_models
16
+ end
17
+
18
+ def each(&block)
19
+ results.each(&block)
20
+ end
21
+
22
+ delegate :results, :total, :facet, :to => :executed_sunspot
23
+ alias_method :all, :results
24
+
25
+ def result_ids
26
+ executed_sunspot.hits.map(&:primary_key)
27
+ end
28
+
29
+ def order_by(name, type=:asc)
30
+ configuration.scope :runtime do |sunspot|
31
+ sunspot.order_by(name)
32
+ end
33
+ end
34
+ alias_method :order, :order_by
35
+
36
+ def limit(number)
37
+ paginate(:per_page => number)
38
+ end
39
+ alias_method :per_page, :limit
40
+ alias_method :per, :limit
41
+
42
+ def page(number)
43
+ paginate(:page => number)
44
+ end
45
+
46
+ def paginate(params)
47
+ configuration.scope :runtime do |sunspot|
48
+ sunspot.paginate(params)
49
+ end
50
+ end
51
+
52
+ def scoped
53
+ default.runtime
54
+ end
55
+
56
+ def boost_by(field, options={})
57
+ boostificator = Boostificator.new(field, options)
58
+ configuration.scope :runtime do |sunspot|
59
+ boostificator.adjust_solr_params(sunspot)
60
+ end
61
+ end
62
+
63
+ def execute
64
+ unless @executed
65
+ build_query
66
+ set_facets
67
+ sunspot.execute
68
+ @executed = true
69
+ end
70
+ end
71
+
72
+ def executed_sunspot
73
+ execute
74
+ sunspot
75
+ end
76
+
77
+ private
78
+
79
+ def build_query
80
+ scope_chain.uniq.each do |scope_name|
81
+ configuration.scopes[scope_name].each do |block|
82
+ sunspot.build do |sunspot|
83
+ case block.arity
84
+ when 0
85
+ sunspot.instance_eval(&block)
86
+ when 1
87
+ block.call(sunspot)
88
+ else
89
+ raise ArgumentError.new "arity > 1 not supported"
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ def set_facets
97
+ configuration.facets.each_pair do |facet_name, block|
98
+ sunspot.build do |search|
99
+ search.instance_eval do |search|
100
+ search.facet facet_name, &block
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def method_missing(name, *args, &block)
107
+ if configuration.scopes.include?(name)
108
+ scope_chain << name
109
+ return self
110
+ end
111
+ return results.send(name, *args, &block) if results.respond_to?(name)
112
+ super
113
+ end
114
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>HasSearcher</title>
5
+ <%= stylesheet_link_tag "has_searcher/application", :media => "all" %>
6
+ <%= javascript_include_tag "has_searcher/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ HasSearcher::Engine.routes.draw do
2
+ end
@@ -0,0 +1,5 @@
1
+ module HasSearcher
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace HasSearcher
4
+ end
5
+ end
@@ -1,3 +1,3 @@
1
1
  module HasSearcher
2
- VERSION = "0.0.17"
2
+ VERSION = "0.0.90"
3
3
  end
data/lib/has_searcher.rb CHANGED
@@ -1,19 +1,14 @@
1
- module HasSearcher
2
- autoload :Base, 'has_searcher/base'
3
- autoload :Helpers, 'has_searcher/helpers'
4
- end
1
+ require "has_searcher/engine"
5
2
 
6
- class ActionController::Base
7
- def self.has_searcher
8
- HasSearcher::Base.has_searcher(self)
3
+ module HasSearcher
4
+ @@searchers = {}
5
+ def self.create_searcher(name, &block)
6
+ @@searchers[name] = block
9
7
  end
10
- end
11
-
12
- require 'has_searcher/formtastic' rescue nil
13
8
 
14
- %w{ models controllers }.each do |dir|
15
- path = File.join(File.dirname(__FILE__), 'app', dir)
16
- $LOAD_PATH << path
17
- ActiveSupport::Dependencies.autoload_paths << path
18
- ActiveSupport::Dependencies.autoload_once_paths.delete(path)
9
+ def self.searcher(name, params={})
10
+ (Searcher.new &@@searchers[name]).tap do |searcher|
11
+ searcher.search_object.attributes = params
12
+ end
13
+ end
19
14
  end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :has_searcher do
3
+ # # Task goes here
4
+ # end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: has_searcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.17
4
+ version: 0.0.90
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,40 +9,99 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-27 00:00:00.000000000 Z
12
+ date: 2012-07-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &14301560 !ruby/object:Gem::Requirement
16
+ requirement: &6913540 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *6913540
25
+ - !ruby/object:Gem::Dependency
26
+ name: sqlite3
27
+ requirement: &6913100 !ruby/object:Gem::Requirement
17
28
  none: false
18
29
  requirements:
19
30
  - - ! '>='
20
31
  - !ruby/object:Gem::Version
21
32
  version: '0'
22
- type: :runtime
33
+ type: :development
23
34
  prerelease: false
24
- version_requirements: *14301560
25
- description: ! "This gem adds ability to construct search objects for indexed models.\n
26
- \ It works with sunspot, inherited_resources and formtastic"
35
+ version_requirements: *6913100
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec-rails
38
+ requirement: &7006040 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *7006040
47
+ - !ruby/object:Gem::Dependency
48
+ name: sunspot_matchers
49
+ requirement: &7005240 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *7005240
58
+ - !ruby/object:Gem::Dependency
59
+ name: sunspot_rails
60
+ requirement: &7004020 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 2.0.0.pre
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *7004020
69
+ - !ruby/object:Gem::Dependency
70
+ name: sunspot_solr
71
+ requirement: &7003340 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 2.0.0.pre
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *7003340
80
+ description: ! "This gem adds ability to construct search objects for indexed models,
81
+ build search forms and execute searches.\n It works with sunspot,
82
+ inherited_resources and simple_form/formtastic"
27
83
  email:
28
84
  - lda@openteam.ru
29
85
  executables: []
30
86
  extensions: []
31
87
  extra_rdoc_files: []
32
88
  files:
33
- - .gitignore
34
- - Gemfile
35
- - Rakefile
36
- - has_searcher.gemspec
37
- - lib/app/controllers/crud_controller.rb
38
- - lib/app/controllers/suggestions_controller.rb
39
- - lib/app/models/boostificator.rb
40
- - lib/app/models/search.rb
41
- - lib/has_searcher.rb
42
- - lib/has_searcher/base.rb
43
- - lib/has_searcher/formtastic.rb
44
- - lib/has_searcher/helpers.rb
89
+ - app/views/layouts/has_searcher/application.html.erb
90
+ - app/assets/stylesheets/has_searcher/application.css
91
+ - app/controllers/has_searcher/application_controller.rb
92
+ - app/models/searcher/configuration.rb
93
+ - app/models/searcher/model.rb
94
+ - app/models/searcher/boostificator.rb
95
+ - app/models/searcher.rb
96
+ - app/helpers/has_searcher/application_helper.rb
97
+ - config/routes.rb
98
+ - lib/tasks/has_searcher_tasks.rake
99
+ - lib/has_searcher/engine.rb
45
100
  - lib/has_searcher/version.rb
101
+ - lib/has_searcher.rb
102
+ - MIT-LICENSE
103
+ - Rakefile
104
+ - README.rdoc
46
105
  homepage: http://github.com/openteam/has_searcher
47
106
  licenses: []
48
107
  post_install_message:
@@ -57,7 +116,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
116
  version: '0'
58
117
  segments:
59
118
  - 0
60
- hash: -2828897147514902018
119
+ hash: -759190286511194393
61
120
  required_rubygems_version: !ruby/object:Gem::Requirement
62
121
  none: false
63
122
  requirements:
@@ -66,9 +125,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
125
  version: '0'
67
126
  segments:
68
127
  - 0
69
- hash: -2828897147514902018
128
+ hash: -759190286511194393
70
129
  requirements: []
71
- rubyforge_project: has_searcher
130
+ rubyforge_project:
72
131
  rubygems_version: 1.8.15
73
132
  signing_key:
74
133
  specification_version: 3
data/.gitignore DELETED
@@ -1,5 +0,0 @@
1
- *.gem
2
- .bundle
3
- Gemfile.lock
4
- pkg/*
5
- bin/*
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in has_searcher.gemspec
4
- gemspec
data/has_searcher.gemspec DELETED
@@ -1,23 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "has_searcher/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "has_searcher"
7
- s.version = HasSearcher::VERSION
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ["Dmitry Lihachev"]
10
- s.email = ["lda@openteam.ru"]
11
- s.homepage = "http://github.com/openteam/has_searcher"
12
- s.summary = %q{Adds ability to construct search objects for indexed models}
13
- s.description = %q{This gem adds ability to construct search objects for indexed models.
14
- It works with sunspot, inherited_resources and formtastic}
15
-
16
- s.add_dependency "rails"
17
- s.rubyforge_project = "has_searcher"
18
-
19
- s.files = `git ls-files`.split("\n")
20
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
- s.require_paths = ["lib"]
23
- end
@@ -1,56 +0,0 @@
1
- # encoding: utf-8
2
-
3
- class SearchController < ApplicationController
4
- inherit_resources
5
-
6
- helper_method :search_object_for
7
-
8
- protected
9
-
10
- def collection
11
- get_collection_ivar || set_collection_ivar(search_and_paginate_collection)
12
- end
13
-
14
- def search_and_paginate_collection
15
- if params[:utf8]
16
- search_object = search_object_for(resource_instance_name)
17
- search_object.pagination = paginate_options
18
- search_object.results
19
- else
20
- end_of_association_chain.paginate(paginate_options)
21
- end
22
- end
23
-
24
- def paginate_options(options={})
25
- {
26
- :page => params[:page],
27
- :per_page => per_page
28
- }.merge(options)
29
- end
30
-
31
- def per_page
32
- 20
33
- end
34
-
35
- def render_new_button?
36
- respond_to? :new
37
- end
38
-
39
- def searcher_name(name)
40
- "#{name}_search"
41
- end
42
-
43
- def create_searcher(searcher_name)
44
- begin
45
- searcher_clazz = searcher_name.classify.constantize
46
- searcher_clazz.new(params[searcher_name]) do | searcher |
47
- searcher_clazz.column_names.each do | column_name |
48
- searcher[column_name] ||= params[column_name]
49
- end
50
- end
51
- rescue NameError
52
- end
53
- end
54
-
55
- end
56
-
@@ -1,21 +0,0 @@
1
- class SuggestionsController < CrudController
2
-
3
- def index
4
- render :text => suggestions.to_json
5
- end
6
-
7
-
8
- protected
9
-
10
- def suggestions
11
- collection.map do | suggest |
12
- { :id => suggest.id, :value => suggest.term }
13
- end
14
- end
15
-
16
- def resource_instance_name
17
- @resource_instance_name ||= params.delete(:model)
18
- end
19
-
20
-
21
- end
@@ -1,106 +0,0 @@
1
- class Search < ActiveRecord::Base
2
-
3
- attr_accessor :pagination
4
-
5
- class << self
6
- def columns
7
- @columns ||= [];
8
- end
9
-
10
- def column(name, sql_type = nil, default = nil, null = true)
11
- columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default,
12
- sql_type.to_s, null)
13
- end
14
-
15
- def column_defaults
16
- columns.map(&:name).inject({}) do | hash, name | hash[name] = nil; hash end
17
- end
18
-
19
- def columns_hash
20
- columns.inject({}) do | hash, column | hash[column.name] = column; hash end
21
- end
22
- end
23
-
24
- def pagination
25
- @pagination ||= {}
26
- @pagination.merge! per_page: per_page if respond_to? :per_page
27
- @pagination
28
- end
29
-
30
- delegate :results, :to => :search
31
- delegate :total, :to => :search
32
-
33
- def result_ids
34
- search.hits.map(&:primary_key)
35
- end
36
-
37
- protected
38
-
39
- def search
40
- Sunspot.search klass do | search |
41
- search.keywords keywords if search_columns.delete("keywords")
42
- search_columns.each do | column |
43
- value = normalize(column)
44
- if column_for_attribute(column).type == :text && self.class.serialized_attributes[column] != Array
45
- if fuzzy?(value)
46
- search.adjust_solr_params do |params|
47
- params[:q] = value.split(/ /).map{ |value| "#{column}_text:#{value}"}.join(' ')
48
- end
49
- else
50
- search.keywords value, :fields => column
51
- end
52
- else
53
- case column
54
- when /_lt$/
55
- search.with(column[0..-4]).less_than(value)
56
- when /_gt$/
57
- search.with(column[0..-4]).greater_than(value)
58
- else
59
- search.with column, value
60
- end
61
- end
62
- end
63
- additional_search(search)
64
- search.order_by *order_by.split(' ') if respond_to?(:order_by) && order_by.present?
65
- search.paginate pagination if pagination.try(:any?)
66
- end
67
- end
68
-
69
- def additional_search(search)
70
- end
71
-
72
- def save(validate = true)
73
- validate ? valid? : true
74
- end
75
-
76
- def search_columns
77
- @search_columns ||= (self.class.column_names - %w[per_page order_by]).select{ |column| normalize(column).present? }
78
- end
79
-
80
- def normalize(column)
81
- if respond_to?("normalize_#{column}")
82
- send "normalize_#{column}"
83
- elsif self.class.serialized_attributes[column] == Array
84
- [*self.send("#{column}_before_type_cast")].select(&:present?)
85
- elsif column_for_attribute(column).type == :integer
86
- self[column].try(:zero?) ? nil : self[column]
87
- elsif column_for_attribute(column).type == :text && column =~ /term$/
88
- normalize_term_column(self[column])
89
- else
90
- self[column]
91
- end
92
- end
93
-
94
- def normalize_term_column(text)
95
- text.gsub(/[^[:alnum:]~]+/, ' ').strip if text
96
- end
97
-
98
- def fuzzy?(text)
99
- text =~ /~/
100
- end
101
-
102
- def klass
103
- self.class.model_name.classify.gsub(/Search$/, '').constantize
104
- end
105
-
106
- end
@@ -1,11 +0,0 @@
1
- class HasSearcher::Base < ::ApplicationController
2
- def self.has_searcher(base)
3
- base.class_eval do
4
- include HasSearcher::Helpers
5
- helper_method :searcher_for
6
- helper_method :searcher
7
- end
8
-
9
- end
10
- has_searcher(self)
11
- end
@@ -1,72 +0,0 @@
1
- begin
2
- require 'formtastic'
3
-
4
- module Formtastic
5
- module Helpers
6
- module FormHelper
7
- def semantic_search_form_for(name, *args, &proc)
8
- options = args.extract_options!
9
- options.reverse_merge! :html => {:method => :get}
10
- url = params[:controller].sub(/\/\w+$/, '').split("/").map(&:underscore)
11
- options[:url] ||= url.push name.to_s.pluralize
12
- semantic_form_for searcher_for(name), *(args << options), &proc
13
- end
14
- end
15
- end
16
-
17
- module SemanticFormHelper
18
- def semantic_search_form_for(*args)
19
- Formtastic::Helpers::FormHelper.semantic_search_form_for(args)
20
- end
21
- end
22
-
23
- class SemanticFormBuilder
24
- def search_button(options={})
25
- commit_button I18n.t('search'), options.merge(button_html: {name: nil},
26
- wrapper_html: {class: 'button'})
27
- end
28
-
29
- def default_input_type_with_text_as_string_on_search(method, options={})
30
- if object.is_a?(Search) && object.class.respond_to?(:has_enum?) && !object.class.has_enum?(method) && object.column_for_attribute(method).try(:type) == :text
31
- :string
32
- else
33
- default_input_type_without_text_as_string_on_search(method, options)
34
- end
35
- end
36
-
37
- alias_method_chain :default_input_type, :text_as_string_on_search
38
-
39
- def inputs_with_search(*args, &block)
40
- if args.empty? && object.is_a?(Search)
41
- args = object.class.column_names.collect do | column |
42
- if belongs_to? column
43
- column = column.gsub /_id$/, ''
44
- end
45
- column
46
- end.map(&:to_sym)
47
- args -= [:term, :order_by, :per_page]
48
- end
49
- inputs_without_search(*args, &block)
50
- end
51
-
52
- alias_method_chain :inputs, :search
53
-
54
- def buttons_with_search(*args, &block)
55
- args = :search if args.empty? && object.is_a?(Search)
56
- buttons_without_search(*args, &block)
57
- end
58
-
59
- alias_method_chain :buttons, :search
60
-
61
- protected
62
-
63
- def belongs_to?(method)
64
- method = method.to_s
65
- method =~ /_id$/ &&
66
- (reflect = object.class.reflect_on_association(method.gsub(/_id$/, '').to_sym)) &&
67
- reflect.macro == :belongs_to
68
- end
69
- end
70
- end
71
- rescue LoadError
72
- end
@@ -1,33 +0,0 @@
1
- module HasSearcher::Helpers
2
-
3
- protected
4
-
5
- def searcher
6
- @searcher ||= searcher_for(resource_instance_name)
7
- end
8
-
9
- def searcher_for(name)
10
- instance_variable_get("@#{searcher_name(name)}") ||
11
- instance_variable_set("@#{searcher_name(name)}", create_searcher(searcher_name(name)))
12
- end
13
-
14
- private
15
-
16
- def searcher_name(name)
17
- "#{name}_search"
18
- end
19
-
20
- def create_searcher(searcher_name)
21
- begin
22
- searcher_clazz = searcher_name.classify.constantize
23
- rescue NameError
24
- return
25
- end
26
- searcher_clazz.new(params[searcher_name]) do | searcher |
27
- searcher_clazz.column_names.each do | column_name |
28
- searcher.send("#{column_name}=", params[column_name]) if searcher.send(column_name).blank?
29
- end
30
- end
31
- end
32
-
33
- end