has_searcher 0.0.17 → 0.0.90

Sign up to get free protection for your applications and to get access to all the features.
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