has_searcher 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in has_searcher.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,22 @@
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.rubyforge_project = "has_searcher"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,56 @@
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
+
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,68 @@
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
+ end
15
+
16
+ delegate :results, :to => :search
17
+
18
+ def result_ids
19
+ search.hits.map(&:primary_key)
20
+ end
21
+
22
+ protected
23
+
24
+ def search
25
+ klass.search do | search |
26
+ search.keywords normalize_text(keywords) if search_columns.delete("keywords")
27
+ search_columns.each do | column |
28
+ if column_for_attribute(column).type == :text
29
+ search.keywords normalize(column), :fields => column
30
+ else
31
+ search.with column, normalize(column)
32
+ end
33
+ end
34
+ search.paginate pagination if pagination.try(:any?)
35
+ end
36
+ end
37
+
38
+ def save(validate = true)
39
+ validate ? valid? : true
40
+ end
41
+
42
+ def search_columns
43
+ @search_columns ||= self.class.column_names.select{ |column| normalize(column).present? }
44
+ end
45
+
46
+ def normalize(column)
47
+ if respond_to? "normalize_#{column}"
48
+ send "normalize_#{column}"
49
+ elsif self.class.serialized_attributes[column] == Array
50
+ [*self.send("#{column}_before_type_cast")].select(&:present?)
51
+ elsif column_for_attribute(column).type == :integer
52
+ self[column].try(:zero?) ? nil : self[column]
53
+ elsif column_for_attribute(column).type == :text && column == "term"
54
+ normalize_text(self[column])
55
+ else
56
+ self[column]
57
+ end
58
+ end
59
+
60
+ def normalize_text(text)
61
+ text.gsub /-/, ' ' if text
62
+ end
63
+
64
+ def klass
65
+ self.class.model_name.classify.gsub(/Search$/, '').constantize
66
+ end
67
+
68
+ end
@@ -0,0 +1,10 @@
1
+ class HasSearcher::Base < ::ApplicationController
2
+ def self.has_searcher(base)
3
+ base.class_eval do
4
+ include HasSearcher::Helpers
5
+ helper_method :searcher
6
+ end
7
+
8
+ end
9
+ has_searcher(self)
10
+ end
@@ -0,0 +1,62 @@
1
+ require 'formtastic'
2
+
3
+ module Formtastic
4
+ module SemanticFormHelper
5
+ def semantic_search_form_for(name, *args, &proc)
6
+ options = args.extract_options!
7
+ options.reverse_merge! :html => {:method => :get}
8
+ url = params[:controller].sub(/\/\w+$/, '').split("/").map(&:underscore)
9
+ options[:url] ||= url.push name.to_s.pluralize
10
+ semantic_form_for search_object_for(name), *(args << options), &proc
11
+ end
12
+ end
13
+
14
+ class SemanticFormBuilder
15
+ def search_button(options={})
16
+ commit_button I18n.t('search'), options.merge(button_html: {name: nil},
17
+ wrapper_html: {class: 'button'})
18
+ end
19
+
20
+ def default_input_type_with_text_as_string_on_search(method, options={})
21
+ if object.is_a?(Search) && object.column_for_attribute(method).try(:type) == :text
22
+ :string
23
+ else
24
+ default_input_type_without_text_as_string_on_search(method, options)
25
+ end
26
+ end
27
+
28
+ alias_method_chain :default_input_type, :text_as_string_on_search
29
+
30
+ def inputs_with_search(*args, &block)
31
+ if args.empty? && object.is_a?(Search)
32
+ args = object.class.column_names.collect do | column |
33
+ if belongs_to? column
34
+ column = column.gsub /_id$/, ''
35
+ end
36
+ column
37
+ end.map(&:to_sym)
38
+ args -= [:term]
39
+ end
40
+ inputs_without_search(*args, &block)
41
+ end
42
+
43
+ alias_method_chain :inputs, :search
44
+
45
+ def buttons_with_search(*args, &block)
46
+ args = :search if args.empty? && object.is_a?(Search)
47
+ buttons_without_search(*args, &block)
48
+ end
49
+
50
+ alias_method_chain :buttons, :search
51
+
52
+ protected
53
+
54
+ def belongs_to?(method)
55
+ method = method.to_s
56
+ method =~ /_id$/ &&
57
+ (reflect = object.class.reflect_on_association(method.gsub(/_id$/, '').to_sym)) &&
58
+ reflect.macro == :belongs_to
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,28 @@
1
+ module HasSearcher::Helpers
2
+
3
+ protected
4
+
5
+ def searcher_for(name)
6
+ instance_variable_get("@#{searcher_name(name)}") ||
7
+ instance_variable_set("@#{searcher_name(name)}", create_searcher(searcher_name(name)))
8
+ end
9
+
10
+ private
11
+
12
+ def searcher_name(name)
13
+ "#{name}_search"
14
+ end
15
+
16
+ def create_searcher(searcher_name)
17
+ begin
18
+ searcher_clazz = searcher_name.classify.constantize
19
+ searcher_clazz.new(params[searcher_name]) do | searcher |
20
+ searcher_clazz.column_names.each do | column_name |
21
+ searcher[column_name] ||= params[column_name]
22
+ end
23
+ end
24
+ rescue NameError
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,3 @@
1
+ module HasSearcher
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,11 @@
1
+ module HasSearcher
2
+
3
+ end
4
+
5
+ class ActionController::Base
6
+ def self.has_searcher
7
+ HasSearcher::Base.has_searcher(self)
8
+ end
9
+ end
10
+
11
+ require 'has_searcher/formtastic' rescue nil
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_searcher
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Dmitry Lihachev
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-04-14 00:00:00 +07:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: |-
22
+ This gem adds ability to construct search objects for indexed models.
23
+ It works with sunspot, inherited_resources and formtastic
24
+ email:
25
+ - lda@openteam.ru
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ 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/search.rb
40
+ - lib/has_searcher.rb
41
+ - lib/has_searcher/base.rb
42
+ - lib/has_searcher/formtastic.rb
43
+ - lib/has_searcher/helpers.rb
44
+ - lib/has_searcher/version.rb
45
+ has_rdoc: true
46
+ homepage: http://github.com/openteam/has_searcher
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options: []
51
+
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project: has_searcher
73
+ rubygems_version: 1.3.7
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Adds ability to construct search objects for indexed models
77
+ test_files: []
78
+