pg_search 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d495a89c4bddfe4c4d367fb1cc8e4c5b1bea048
4
- data.tar.gz: 611249f3cddce656579b5f4618a4d8a26ed77f8d
3
+ metadata.gz: 55ed2cdc0eaecdb0dcb05ee5fcf7e7460556669d
4
+ data.tar.gz: 8ff17add1a0a7c7a16dd6501b6335e5d364b07b4
5
5
  SHA512:
6
- metadata.gz: b6bfca34ff32c71bc153173f6cd5ea293ab35bea8aa55cdabd53388b687e56b273402b2b822789994d378fed58e3591a1a91c724cfc91f1085edba9d988773f6
7
- data.tar.gz: d03fc9fe66c02fb33744ec86ab12ec97d662c3eaff075da0c1b0f6f994e3c3f4c8da47045d4ce227bb6552e8890d95729d1cc679e80115378aabd9f7fd4b2324
6
+ metadata.gz: 1acf5bc208de87a781c1c2ddaa3b44b33609afb8927cd8bbbb256a9a9caf099f3c2507232a0d9f2a9ad45acaf997e3590bbcbac6d3cb4936515e6874c3cb4ea1
7
+ data.tar.gz: d569da3e3f8aa7b205596fbce5d1bd72e0db4dab9576ac9331b810b4dbcefd80f77918a8ce51cfb3e944f63520f4166e86bd5db883b01c0e2b8f97e3bff7018d
data/.rubocop_todo.yml CHANGED
@@ -1,37 +1,84 @@
1
- # This configuration was generated by `rubocop --auto-gen-config`
2
- # on 2014-12-12 15:10:11 -0600 using RuboCop version 0.28.0.
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-01-25 14:11:25 -0600 using RuboCop version 0.36.0.
3
4
  # The point is for the user to remove these configuration records
4
5
  # one by one as the offenses are removed from the code base.
5
6
  # Note that changes in the inspected code, or installation of new
6
7
  # versions of RuboCop, may require this file to be generated again.
7
8
 
9
+ # Offense count: 2
10
+ # Cop supports --auto-correct.
11
+ Lint/UnneededDisable:
12
+ Exclude:
13
+ - 'lib/pg_search/features/tsearch.rb'
14
+ - 'lib/pg_search/scope_options.rb'
15
+
16
+ # Offense count: 1
17
+ # Cop supports --auto-correct.
18
+ Performance/Casecmp:
19
+ Exclude:
20
+ - 'spec/support/database.rb'
21
+
8
22
  # Offense count: 27
9
23
  Style/Documentation:
10
24
  Enabled: false
11
25
 
12
- # Offense count: 16
26
+ # Offense count: 3
13
27
  # Cop supports --auto-correct.
14
- Style/NumericLiterals:
15
- MinDigits: 6
28
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
29
+ # SupportedStyles: when_needed, always
30
+ Style/FrozenStringLiteralComment:
31
+ Exclude:
32
+ - 'lib/pg_search/migration/associated_against_generator.rb'
33
+ - 'lib/pg_search/migration/dmetaphone_generator.rb'
34
+ - 'lib/pg_search/version.rb'
16
35
 
17
- # Offense count: 2
36
+ # Offense count: 1
37
+ Style/IfInsideElse:
38
+ Exclude:
39
+ - 'lib/pg_search/multisearchable.rb'
40
+
41
+ # Offense count: 26
18
42
  # Cop supports --auto-correct.
19
- # Configuration parameters: EnforcedStyle, SupportedStyles.
20
- Style/PercentQLiterals:
43
+ # Configuration parameters: SupportedStyles, IndentationWidth.
44
+ # SupportedStyles: special_inside_parentheses, consistent, align_brackets
45
+ Style/IndentArray:
46
+ EnforcedStyle: consistent
47
+
48
+ # Offense count: 3
49
+ # Cop supports --auto-correct.
50
+ # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
51
+ # SupportedStyles: aligned, indented
52
+ Style/MultilineMethodCallIndentation:
21
53
  Enabled: false
22
54
 
55
+ # Offense count: 2
56
+ # Cop supports --auto-correct.
57
+ Style/MutableConstant:
58
+ Exclude:
59
+ - 'lib/pg_search/configuration.rb'
60
+ - 'lib/pg_search/scope_options.rb'
61
+
62
+ # Offense count: 16
63
+ # Cop supports --auto-correct.
64
+ Style/NumericLiterals:
65
+ MinDigits: 6
66
+
23
67
  # Offense count: 1
24
68
  # Cop supports --auto-correct.
25
69
  Style/PerlBackrefs:
26
- Enabled: false
70
+ Exclude:
71
+ - 'lib/pg_search/scope_options.rb'
27
72
 
28
73
  # Offense count: 1
29
74
  # Cop supports --auto-correct.
30
75
  Style/Proc:
31
- Enabled: false
76
+ Exclude:
77
+ - 'lib/pg_search/document.rb'
32
78
 
33
- # Offense count: 4
79
+ # Offense count: 5
34
80
  # Configuration parameters: EnforcedStyle, SupportedStyles.
81
+ # SupportedStyles: compact, exploded
35
82
  Style/RaiseArgs:
36
83
  Enabled: false
37
84
 
@@ -39,78 +86,114 @@ Style/RaiseArgs:
39
86
  # Cop supports --auto-correct.
40
87
  # Configuration parameters: AllowMultipleReturnValues.
41
88
  Style/RedundantReturn:
42
- Enabled: false
89
+ Exclude:
90
+ - 'lib/pg_search/scope_options.rb'
43
91
 
44
- # Offense count: 10
92
+ # Offense count: 11
45
93
  # Cop supports --auto-correct.
46
94
  # Configuration parameters: EnforcedStyle, SupportedStyles.
95
+ # SupportedStyles: only_raise, only_fail, semantic
47
96
  Style/SignalException:
48
- Enabled: false
97
+ Exclude:
98
+ - 'lib/pg_search.rb'
99
+ - 'lib/pg_search/configuration.rb'
100
+ - 'lib/pg_search/features/tsearch.rb'
101
+ - 'lib/pg_search/multisearch/rebuilder.rb'
102
+ - 'lib/pg_search/normalizer.rb'
103
+ - 'lib/pg_search/scope_options.rb'
104
+ - 'lib/pg_search/tasks.rb'
105
+ - 'spec/lib/pg_search_spec.rb'
106
+ - 'spec/support/database.rb'
49
107
 
50
108
  # Offense count: 2
51
109
  # Cop supports --auto-correct.
52
110
  Style/SpaceAfterComma:
53
- Enabled: false
111
+ Exclude:
112
+ - 'lib/pg_search/configuration.rb'
113
+ - 'lib/pg_search/tasks.rb'
54
114
 
55
115
  # Offense count: 1
56
116
  # Cop supports --auto-correct.
57
117
  # Configuration parameters: EnforcedStyle, SupportedStyles.
118
+ # SupportedStyles: space, no_space
58
119
  Style/SpaceAroundEqualsInParameterDefault:
59
120
  Enabled: false
60
121
 
61
- # Offense count: 1
122
+ # Offense count: 4
62
123
  # Cop supports --auto-correct.
63
124
  # Configuration parameters: EnforcedStyle, SupportedStyles.
125
+ # SupportedStyles: space, no_space
64
126
  Style/SpaceBeforeBlockBraces:
65
127
  Enabled: false
66
128
 
67
- # Offense count: 2
129
+ # Offense count: 3
68
130
  # Cop supports --auto-correct.
69
131
  # Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
132
+ # SupportedStyles: space, no_space
70
133
  Style/SpaceInsideBlockBraces:
71
134
  Enabled: false
72
135
 
73
136
  # Offense count: 76
74
137
  # Cop supports --auto-correct.
75
138
  # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles.
139
+ # SupportedStyles: space, no_space
76
140
  Style/SpaceInsideHashLiteralBraces:
77
141
  Enabled: false
78
142
 
79
143
  # Offense count: 2
80
144
  # Cop supports --auto-correct.
81
145
  Style/SpaceInsideParens:
82
- Enabled: false
146
+ Exclude:
147
+ - 'spec/lib/pg_search/multisearch/rebuilder_spec.rb'
83
148
 
84
149
  # Offense count: 3
85
150
  # Cop supports --auto-correct.
151
+ # Configuration parameters: SupportedStyles.
152
+ # SupportedStyles: use_perl_names, use_english_names
86
153
  Style/SpecialGlobalVars:
87
- Enabled: false
154
+ EnforcedStyle: use_english_names
88
155
 
89
156
  # Offense count: 2
90
157
  # Cop supports --auto-correct.
91
158
  # Configuration parameters: IgnoredMethods.
159
+ # IgnoredMethods: respond_to
92
160
  Style/SymbolProc:
93
- Enabled: false
161
+ Exclude:
162
+ - 'lib/pg_search/features/feature.rb'
163
+ - 'lib/pg_search/multisearch/rebuilder.rb'
94
164
 
95
- # Offense count: 4
165
+ # Offense count: 5
96
166
  # Cop supports --auto-correct.
97
167
  # Configuration parameters: EnforcedStyle, SupportedStyles.
168
+ # SupportedStyles: final_newline, final_blank_line
98
169
  Style/TrailingBlankLines:
99
- Enabled: false
170
+ Exclude:
171
+ - 'Guardfile'
172
+ - 'lib/pg_search/extensions/arel.rb'
173
+ - 'lib/pg_search/migration/multisearch_generator.rb'
174
+ - 'lib/pg_search/multisearch.rb'
175
+ - 'spec/integration/single_table_inheritance_spec.rb'
100
176
 
101
177
  # Offense count: 9
102
178
  # Cop supports --auto-correct.
103
179
  # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
104
- Style/TrailingComma:
105
- Enabled: false
180
+ # SupportedStyles: comma, consistent_comma, no_comma
181
+ Style/TrailingCommaInLiteral:
182
+ Exclude:
183
+ - 'spec/integration/pg_search_spec.rb'
184
+ - 'spec/lib/pg_search/features/dmetaphone_spec.rb'
185
+ - 'spec/lib/pg_search/features/tsearch_spec.rb'
106
186
 
107
- # Offense count: 6
187
+ # Offense count: 2
108
188
  # Cop supports --auto-correct.
109
189
  Style/UnneededPercentQ:
110
- Enabled: false
190
+ Exclude:
191
+ - 'pg_search.gemspec'
111
192
 
112
193
  # Offense count: 3
113
194
  # Cop supports --auto-correct.
114
- # Configuration parameters: WordRegex.
195
+ # Configuration parameters: SupportedStyles, WordRegex.
196
+ # SupportedStyles: percent, brackets
115
197
  Style/WordArray:
116
- MinSize: 2
198
+ EnforcedStyle: percent
199
+ MinSize: 3
data/.travis.yml CHANGED
@@ -2,10 +2,11 @@ language: ruby
2
2
  sudo: false
3
3
 
4
4
  rvm:
5
- - "1.9"
6
- - "2.0"
7
- - "2.1"
5
+ - "2.3.1"
8
6
  - "2.2"
7
+ - "2.1"
8
+ - "2.0"
9
+ - "1.9"
9
10
  - jruby-19mode
10
11
  - jruby-9.0.0.0
11
12
 
data/CHANGELOG.md CHANGED
@@ -1,9 +1,14 @@
1
1
  # pg_search changelog
2
2
 
3
+ ## 1.0.6
4
+ * Add support for highlighting the matching portion of a search result. (Jose Galisteo)
5
+ * Add `:update_if` option to control when PgSearch::Document gets updated. (Adam Becker)
6
+ * Add `:additional_attributes` option for adding additional attributes to PgSearch::Document
7
+
3
8
  ## 1.0.5
4
9
 
5
- * Clean up rank table aliasing (Adam Milligan)
6
- * Fix issue when using `#with_pg_search_rank` across a join (Reid Lynch)
10
+ * Clean up rank table aliasing. (Adam Milligan)
11
+ * Fix issue when using `#with_pg_search_rank` across a join. (Reid Lynch)
7
12
 
8
13
  ## 1.0.4
9
14
 
data/Gemfile CHANGED
@@ -12,13 +12,6 @@ end
12
12
 
13
13
  gem 'activerecord', ENV['ACTIVE_RECORD_VERSION'] if ENV['ACTIVE_RECORD_VERSION']
14
14
 
15
- group :development do
16
- gem 'guard-rspec', :require => false
17
- gem 'rb-inotify', :require => false
18
- gem 'rb-fsevent', :require => false
19
- gem 'rb-fchange', :require => false
20
- end
21
-
22
15
  group :test do
23
16
  gem "codeclimate-test-reporter", require: nil
24
17
  end
data/README.md CHANGED
@@ -7,6 +7,7 @@
7
7
  [![Dependency Status](https://img.shields.io/gemnasium/Casecommons/pg_search.svg?style=flat)](https://gemnasium.com/Casecommons/pg_search)
8
8
  [![Inline docs](http://inch-ci.org/github/Casecommons/pg_search.svg?branch=master&style=flat)](http://inch-ci.org/github/Casecommons/pg_search)
9
9
  [![Join the chat at https://gitter.im/Casecommons/pg_search](https://img.shields.io/badge/gitter-join%20chat-blue.svg)](https://gitter.im/Casecommons/pg_search?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
10
+ [![Stories in Ready](https://badge.waffle.io/Casecommons/pg_search.svg?label=ready&title=Ready)](https://waffle.io/Casecommons/pg_search)
10
11
 
11
12
  ## DESCRIPTION
12
13
 
@@ -239,10 +240,12 @@ receive SQL requests when necessary.
239
240
  ```ruby
240
241
  PgSearch.multisearch("Bertha").limit(10)
241
242
  PgSearch.multisearch("Juggler").where(:searchable_type => "Occupation")
242
- PgSearch.multisearch("Alamo").page(3).per_page(30)
243
+ PgSearch.multisearch("Alamo").page(3).per(30)
243
244
  PgSearch.multisearch("Diagonal").find_each do |document|
244
245
  puts document.searchable.updated_at
245
246
  end
247
+ PgSearch.multisearch("Moro").reorder("").group(:searchable_type).count(:all)
248
+ PgSearch.multisearch("Square").includes(:searchable)
246
249
  ```
247
250
 
248
251
  #### Configuring multi-search
@@ -733,6 +736,34 @@ one_close = Person.create!(:name => 'leigh heinz')
733
736
  Person.search('ash hines') # => [exact, one_exact_one_close, one_exact]
734
737
  ```
735
738
 
739
+ ##### :highlight (PostgreSQL 9.0 and newer only)
740
+
741
+ Adding .with_pg_search_highlight after the pg_search_scope you can access to
742
+ `pg_highlight` attribute for each object.
743
+
744
+
745
+ ```ruby
746
+ class Person < ActiveRecord::Base
747
+ include PgSearch
748
+ pg_search_scope :search,
749
+ :against => :bio,
750
+ :using => {
751
+ :tsearch => {
752
+ :start_sel => '<b>',
753
+ :stop_sel => '</b>'
754
+ }
755
+ }
756
+ end
757
+
758
+ Person.create!(:bio => "Born in rural Alberta, where the buffalo roam.")
759
+
760
+ first_match = Person.search("Alberta").with_pg_search_highlight.first
761
+ first_match.pg_search_highlight # => "Born in rural <b>Alberta</b>, where the buffalo roam."
762
+ ```
763
+
764
+ By default, it will add the delimiters `<b>` and `</b>` around the matched text. You can customize these delimiters and the number of fragments returned with the `:start_sel`, `stop_sel`, and `max_fragments` options.
765
+
766
+
736
767
  #### :dmetaphone (Double Metaphone soundalike search)
737
768
 
738
769
  [Double Metaphone](http://en.wikipedia.org/wiki/Double_Metaphone) is an
@@ -804,7 +835,9 @@ Website.kinda_spelled_like("Yahoo!") # => [yahooo, yohoo]
804
835
  By default, trigram searches find records which have a similarity of at least 0.3
805
836
  using pg_trgm's calculations. You may specify a custom threshold if you prefer.
806
837
  Higher numbers match more strictly, and thus return fewer results. Lower numbers
807
- match more permissively, letting in more results.
838
+ match more permissively, letting in more results. Please note that setting a trigram
839
+ threshold will force a table scan as the derived query uses the
840
+ `similarity()` function instead of the `%` operator.
808
841
 
809
842
  ```ruby
810
843
  class Vegetable < ActiveRecord::Base
@@ -1068,7 +1101,7 @@ queried table.
1068
1101
  ```ruby
1069
1102
  shirt_brands = ShirtBrand.search_by_name("Penguin")
1070
1103
  .joins(:shirt_sizes)
1071
- .group_by('shirt_brands.id, #{PgSearch::Configuration.alias('shirt_brands')}.rank')
1104
+ .group("shirt_brands.id, #{PgSearch::Configuration.alias('shirt_brands')}.rank")
1072
1105
  ```
1073
1106
 
1074
1107
  ## ATTRIBUTIONS
data/lib/pg_search.rb CHANGED
@@ -73,6 +73,9 @@ module PgSearch
73
73
  when :pg_search_rank
74
74
  raise PgSearchRankNotSelected.new unless respond_to?(:pg_search_rank)
75
75
  read_attribute(:pg_search_rank).to_f
76
+ when :pg_search_highlight
77
+ raise PgSearchHighlightNotSelected.new unless respond_to?(:pg_search_highlight)
78
+ read_attribute(:pg_search_highlight)
76
79
  else
77
80
  super
78
81
  end
@@ -82,6 +85,8 @@ module PgSearch
82
85
  case symbol
83
86
  when :pg_search_rank
84
87
  attributes.key?(:pg_search_rank)
88
+ when :pg_search_highlight
89
+ attributes.key?(:pg_search_highlight)
85
90
  else
86
91
  super
87
92
  end
@@ -90,9 +95,15 @@ module PgSearch
90
95
  class NotSupportedForPostgresqlVersion < StandardError; end
91
96
 
92
97
  class PgSearchRankNotSelected < StandardError
98
+ def message
99
+ "You must chain .with_pg_search_rank after the pg_search_scope to access the pg_search_rank attribute on returned records" # rubocop:disable Metrics/LineLength
100
+ end
101
+ end
102
+
103
+ class PgSearchHighlightNotSelected < StandardError
93
104
  # rubocop:disable Metrics/LineLength
94
105
  def message
95
- "You must chain .with_pg_search_rank after the pg_search_scope to access the pg_search_rank attribute on returned records"
106
+ "You must chain .with_pg_search_highlight after the pg_search_scope to access the pg_search_highlight attribute on returned records"
96
107
  end
97
108
  end
98
109
  end
@@ -7,9 +7,6 @@ module PgSearch
7
7
  self.table_name = 'pg_search_documents'
8
8
  belongs_to :searchable, :polymorphic => true
9
9
 
10
- before_validation :update_content,
11
- :unless => Proc.new { |doc| doc.searchable.nil? }
12
-
13
10
  # The logger might not have loaded yet.
14
11
  # https://github.com/Casecommons/pg_search/issues/26
15
12
  def self.logger
@@ -25,13 +22,5 @@ module PgSearch
25
22
 
26
23
  {:against => :content}.merge(options)
27
24
  }
28
-
29
- private
30
-
31
- def update_content
32
- methods = Array(searchable.pg_search_multisearchable_options[:against])
33
- searchable_text = methods.map { |symbol| searchable.send(symbol) }.join(" ")
34
- self.content = searchable_text
35
- end
36
25
  end
37
26
  end
@@ -3,19 +3,15 @@ require "active_support/core_ext/module/delegation"
3
3
 
4
4
  module PgSearch
5
5
  module Features
6
- class TSearch < Feature
6
+ class TSearch < Feature # rubocop:disable Metrics/ClassLength
7
7
  def self.valid_options
8
- super + [:dictionary, :prefix, :negation, :any_word, :normalization, :tsvector_column]
8
+ super + [:dictionary, :prefix, :negation, :any_word, :normalization, :tsvector_column, :highlight]
9
9
  end
10
10
 
11
11
  def initialize(*args)
12
12
  super
13
-
14
- if options[:prefix] && model.connection.send(:postgresql_version) < 80400 # rubocop:disable Style/GuardClause
15
- raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
16
- Sorry, {:using => {:tsearch => {:prefix => true}}} only works in PostgreSQL 8.4 and above.")
17
- MESSAGE
18
- end
13
+ checks_for_highlight
14
+ checks_for_prefix
19
15
  end
20
16
 
21
17
  def conditions
@@ -28,8 +24,47 @@ module PgSearch
28
24
  arel_wrap(tsearch_rank)
29
25
  end
30
26
 
27
+ def highlight
28
+ arel_wrap(ts_headline)
29
+ end
30
+
31
31
  private
32
32
 
33
+ def checks_for_prefix
34
+ if options[:prefix] && model.connection.send(:postgresql_version) < 80400
35
+ raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
36
+ Sorry, {:using => {:tsearch => {:prefix => true}}} only works in PostgreSQL 8.4 and above.")
37
+ MESSAGE
38
+ end
39
+ end
40
+
41
+ def checks_for_highlight
42
+ if options[:highlight] && model.connection.send(:postgresql_version) < 90000
43
+ raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
44
+ Sorry, {:using => {:tsearch => {:highlight => true}}} only works in PostgreSQL 9.0 and above.")
45
+ MESSAGE
46
+ end
47
+ end
48
+
49
+ def ts_headline
50
+ "ts_headline((#{document}), (#{tsquery}), '#{ts_headline_options}')"
51
+ end
52
+
53
+ def ts_headline_options
54
+ return nil unless options[:highlight].is_a?(Hash)
55
+
56
+ headline_options = map_headline_options
57
+ headline_options.map{|key, value| "#{key} = #{value}" if value }.compact.join(", ")
58
+ end
59
+
60
+ def map_headline_options
61
+ {
62
+ "StartSel" => options[:highlight][:start_sel],
63
+ "StopSel" => options[:highlight][:stop_sel],
64
+ "MaxFragments" => options[:highlight][:max_fragments]
65
+ }
66
+ end
67
+
33
68
  DISALLOWED_TSQUERY_CHARACTERS = /['?\\:]/
34
69
 
35
70
  def tsquery_for_term(unsanitized_term) # rubocop:disable Metrics/AbcSize
@@ -14,6 +14,27 @@ module PgSearch
14
14
  end
15
15
  end
16
16
 
17
+ def searchable_text
18
+ Array(pg_search_multisearchable_options[:against])
19
+ .map { |symbol| send(symbol) }
20
+ .join(" ")
21
+ end
22
+
23
+ def pg_search_document_attrs
24
+ {
25
+ content: searchable_text
26
+ }.tap do |h|
27
+ if (attrs = pg_search_multisearchable_options[:additional_attributes])
28
+ h.merge! attrs.to_proc.call(self)
29
+ end
30
+ end
31
+ end
32
+
33
+ def should_update_pg_search_document?
34
+ conditions = Array(pg_search_multisearchable_options[:update_if])
35
+ conditions.all? { |condition| condition.to_proc.call(self) }
36
+ end
37
+
17
38
  def update_pg_search_document # rubocop:disable Metrics/AbcSize
18
39
  if_conditions = Array(pg_search_multisearchable_options[:if])
19
40
  unless_conditions = Array(pg_search_multisearchable_options[:unless])
@@ -23,10 +44,18 @@ module PgSearch
23
44
  unless_conditions.all? { |condition| !condition.to_proc.call(self) }
24
45
 
25
46
  if should_have_document
26
- pg_search_document ? pg_search_document.save : create_pg_search_document
47
+ create_or_update_pg_search_document
27
48
  else
28
49
  pg_search_document.destroy if pg_search_document
29
50
  end
30
51
  end
52
+
53
+ def create_or_update_pg_search_document
54
+ if !pg_search_document
55
+ create_pg_search_document(pg_search_document_attrs)
56
+ elsif should_update_pg_search_document?
57
+ pg_search_document.update_attributes(pg_search_document_attrs)
58
+ end
59
+ end
31
60
  end
32
61
  end
@@ -21,6 +21,7 @@ module PgSearch
21
21
  .order("#{rank_table_alias}.rank DESC, #{order_within_rank}")
22
22
  .extend(DisableEagerLoading)
23
23
  .extend(WithPgSearchRank)
24
+ .extend(WithPgSearchHighlight[feature_for(:tsearch)])
24
25
  end
25
26
 
26
27
  # workaround for https://github.com/Casecommons/pg_search/issues/14
@@ -30,6 +31,32 @@ module PgSearch
30
31
  end
31
32
  end
32
33
 
34
+ module WithPgSearchHighlight
35
+ def self.[](tsearch)
36
+ Module.new do
37
+ include WithPgSearchHighlight
38
+ define_method(:tsearch) { tsearch }
39
+ end
40
+ end
41
+
42
+ def tsearch
43
+ raise TypeError.new("You need to instantiate this module with []")
44
+ end
45
+
46
+ def with_pg_search_highlight
47
+ scope = self
48
+ scope.select(pg_search_highlight_field)
49
+ end
50
+
51
+ def pg_search_highlight_field
52
+ "(#{highlight}) AS pg_search_highlight, #{table_name}.*"
53
+ end
54
+
55
+ def highlight
56
+ tsearch.highlight.to_sql
57
+ end
58
+ end
59
+
33
60
  module WithPgSearchRank
34
61
  def with_pg_search_rank
35
62
  scope = self
@@ -103,7 +130,7 @@ module PgSearch
103
130
  end
104
131
 
105
132
  def subquery_join
106
- if config.associations.any? # rubocop:disable Style/GuardClause
133
+ if config.associations.any?
107
134
  config.associations.map do |association|
108
135
  association.join(primary_key)
109
136
  end.join(' ')
@@ -1,3 +1,3 @@
1
1
  module PgSearch
2
- VERSION = "1.0.5".freeze
2
+ VERSION = "1.0.6".freeze
3
3
  end
data/pg_search.gemspec CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
3
  require "pg_search/version"
4
4
 
5
5
  Gem::Specification.new do |s|
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_development_dependency 'pry'
26
26
  s.add_development_dependency 'rspec', '>= 3.3'
27
27
  s.add_development_dependency 'with_model', '>= 1.2'
28
- s.add_development_dependency 'rubocop', '>= 0.30.0'
28
+ s.add_development_dependency 'rubocop', '>= 0.36'
29
29
 
30
30
  s.required_ruby_version = ">= 1.9.2"
31
31
  end
@@ -618,6 +618,33 @@ describe "an Active Record model which includes PgSearch" do
618
618
  end
619
619
  end
620
620
 
621
+ describe "highlighting" do
622
+ before do
623
+ ["Strip Down", "Down", "Down and Out", "Won't Let You Down"].each do |name|
624
+ ModelWithPgSearch.create! :content => name
625
+ end
626
+ end
627
+
628
+ context "with highlight turned on" do
629
+ before do
630
+ ModelWithPgSearch.pg_search_scope :search_content,
631
+ :against => :content
632
+ end
633
+
634
+ it "adds a #pg_search_highlight method to each returned model record" do
635
+ result = ModelWithPgSearch.search_content("Strip Down").with_pg_search_highlight.first
636
+
637
+ expect(result.pg_search_highlight).to be_a(String)
638
+ end
639
+
640
+ it "returns excerpts of text where search match occurred" do
641
+ result = ModelWithPgSearch.search_content("Let").with_pg_search_highlight.first
642
+
643
+ expect(result.pg_search_highlight).to eq("Won't <b>Let</b> You Down")
644
+ end
645
+ end
646
+ end
647
+
621
648
  describe "ranking" do
622
649
  before do
623
650
  ["Strip Down", "Down", "Down and Out", "Won't Let You Down"].each do |name|
@@ -3,6 +3,19 @@ require "spec_helper"
3
3
  describe PgSearch::Multisearch::Rebuilder do
4
4
  with_table "pg_search_documents", {}, &DOCUMENTS_SCHEMA
5
5
 
6
+ describe 'when intialized with a model that is not multisearchable' do
7
+ with_model :not_multisearchable
8
+
9
+ it 'raises an exception' do
10
+ expect {
11
+ PgSearch::Multisearch::Rebuilder.new(NotMultisearchable)
12
+ }.to raise_exception(
13
+ PgSearch::Multisearch::ModelNotMultisearchable,
14
+ "NotMultisearchable is not multisearchable. See PgSearch::ClassMethods#multisearchable"
15
+ )
16
+ end
17
+ end
18
+
6
19
  describe "#rebuild" do
7
20
  context "when the model defines .rebuild_pg_search_documents" do
8
21
  context "and multisearchable is not conditional" do
@@ -94,6 +94,148 @@ describe PgSearch::Multisearchable do
94
94
  end
95
95
  end
96
96
  end
97
+
98
+ describe "populating the searchable text" do
99
+ let(:record) { ModelThatIsMultisearchable.new }
100
+ subject { record }
101
+
102
+ before do
103
+ ModelThatIsMultisearchable.multisearchable(multisearchable_options)
104
+ end
105
+
106
+ context "when searching against a single column" do
107
+ let(:multisearchable_options) { {:against => :some_content} }
108
+ let(:text) { "foo bar" }
109
+ before do
110
+ allow(record).to receive(:some_content) { text }
111
+ record.save
112
+ end
113
+
114
+ describe '#content' do
115
+ subject { super().pg_search_document.content }
116
+ it { is_expected.to eq(text) }
117
+ end
118
+ end
119
+
120
+ context "when searching against multiple columns" do
121
+ let(:multisearchable_options) { {:against => [:attr1, :attr2]} }
122
+ before do
123
+ allow(record).to receive(:attr1) { '1' }
124
+ allow(record).to receive(:attr2) { '2' }
125
+ record.save
126
+ end
127
+
128
+ describe '#content' do
129
+ subject { super().pg_search_document.content }
130
+ it { is_expected.to eq("1 2") }
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "populating the searchable attributes" do
136
+ let(:record) { ModelThatIsMultisearchable.new }
137
+ subject { record }
138
+
139
+ before do
140
+ ModelThatIsMultisearchable.multisearchable(multisearchable_options)
141
+ end
142
+
143
+ context "when searching against a single column" do
144
+ let(:multisearchable_options) { {:against => :some_content} }
145
+ let(:text) { "foo bar" }
146
+ before do
147
+ allow(record).to receive(:some_content) { text }
148
+ record.save
149
+ end
150
+
151
+ describe '#content' do
152
+ subject { super().pg_search_document.content }
153
+ it { is_expected.to eq(text) }
154
+ end
155
+ end
156
+
157
+ context "when searching against multiple columns" do
158
+ let(:multisearchable_options) { {:against => [:attr1, :attr2]} }
159
+ before do
160
+ allow(record).to receive(:attr1) { '1' }
161
+ allow(record).to receive(:attr2) { '2' }
162
+ record.save
163
+ end
164
+
165
+ describe '#content' do
166
+ subject { super().pg_search_document.content }
167
+ it { is_expected.to eq("1 2") }
168
+ end
169
+ end
170
+
171
+ context "with additional_attributes" do
172
+ let(:multisearchable_options) do
173
+ {
174
+ :additional_attributes => lambda do |record|
175
+ { foo: record.bar }
176
+ end
177
+ }
178
+ end
179
+ let(:text) { "foo bar" }
180
+
181
+ it "sets the attributes" do
182
+ allow(record).to receive(:bar).and_return(text)
183
+ expect(record)
184
+ .to receive(:create_pg_search_document)
185
+ .with(content: '', foo: text)
186
+ record.save
187
+ end
188
+ end
189
+
190
+ context "when selectively updating" do
191
+ let(:multisearchable_options) do
192
+ {
193
+ :update_if => lambda do |record|
194
+ record.bar?
195
+ end
196
+ }
197
+ end
198
+ let(:text) { "foo bar" }
199
+
200
+ it "creates the document" do
201
+ allow(record).to receive(:bar?).and_return(false)
202
+ expect(record)
203
+ .to receive(:create_pg_search_document)
204
+ .with(content: '')
205
+ record.save
206
+ end
207
+
208
+ context "the document is created" do
209
+ before { record.save }
210
+
211
+ context "update_if returns false" do
212
+ before do
213
+ allow(record).to receive(:bar?).and_return(false)
214
+ end
215
+
216
+ it "does not update the document" do
217
+ expect_any_instance_of(PgSearch::Document)
218
+ .to_not receive(:update_attributes)
219
+
220
+ record.save
221
+ end
222
+ end
223
+
224
+ context "update_if returns true" do
225
+ before do
226
+ allow(record).to receive(:bar?).and_return(true)
227
+ end
228
+
229
+ it "updates the document" do
230
+ expect_any_instance_of(PgSearch::Document)
231
+ .to receive(:update_attributes)
232
+
233
+ record.save
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
97
239
  end
98
240
 
99
241
  describe "a model which is conditionally multisearchable using a Proc" do
@@ -30,7 +30,7 @@ rescue *error_classes
30
30
  puts " createdb pg_search_test"
31
31
  puts "-" * 80
32
32
  end
33
- raise $!
33
+ raise $ERROR_INFO
34
34
  end
35
35
 
36
36
  if ENV["LOGGER"]
@@ -50,7 +50,7 @@ rescue
50
50
  else
51
51
  share_path = `pg_config --sharedir`.strip
52
52
  ActiveRecord::Base.connection.execute File.read(File.join(share_path, 'contrib', "#{name}.sql"))
53
- puts $!.message
53
+ puts $ERROR_INFO.message
54
54
  end
55
55
  rescue => exception
56
56
  at_exit do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Grant Hutchins
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-08-30 00:00:00.000000000 Z
12
+ date: 2016-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -115,14 +115,14 @@ dependencies:
115
115
  requirements:
116
116
  - - ">="
117
117
  - !ruby/object:Gem::Version
118
- version: 0.30.0
118
+ version: '0.36'
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - ">="
124
124
  - !ruby/object:Gem::Version
125
- version: 0.30.0
125
+ version: '0.36'
126
126
  description: PgSearch builds Active Record named scopes that take advantage of PostgreSQL's
127
127
  full text search
128
128
  email:
@@ -184,7 +184,6 @@ files:
184
184
  - spec/lib/pg_search/configuration/association_spec.rb
185
185
  - spec/lib/pg_search/configuration/column_spec.rb
186
186
  - spec/lib/pg_search/configuration/foreign_column_spec.rb
187
- - spec/lib/pg_search/document_spec.rb
188
187
  - spec/lib/pg_search/features/dmetaphone_spec.rb
189
188
  - spec/lib/pg_search/features/trigram_spec.rb
190
189
  - spec/lib/pg_search/features/tsearch_spec.rb
@@ -222,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
221
  version: '0'
223
222
  requirements: []
224
223
  rubyforge_project:
225
- rubygems_version: 2.4.5
224
+ rubygems_version: 2.5.1
226
225
  signing_key:
227
226
  specification_version: 4
228
227
  summary: PgSearch builds Active Record named scopes that take advantage of PostgreSQL's
@@ -235,7 +234,6 @@ test_files:
235
234
  - spec/lib/pg_search/configuration/association_spec.rb
236
235
  - spec/lib/pg_search/configuration/column_spec.rb
237
236
  - spec/lib/pg_search/configuration/foreign_column_spec.rb
238
- - spec/lib/pg_search/document_spec.rb
239
237
  - spec/lib/pg_search/features/dmetaphone_spec.rb
240
238
  - spec/lib/pg_search/features/trigram_spec.rb
241
239
  - spec/lib/pg_search/features/tsearch_spec.rb
@@ -1,56 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe PgSearch::Document do
4
- with_table "pg_search_documents", {}, &DOCUMENTS_SCHEMA
5
-
6
- with_model :Searchable do
7
- table
8
- model do
9
- include PgSearch
10
- multisearchable
11
- end
12
- end
13
-
14
- it { is_expected.to be_an(ActiveRecord::Base) }
15
-
16
- describe "callbacks" do
17
- describe "before_validation" do
18
- subject { document }
19
- let(:document) { PgSearch::Document.new(:searchable => searchable) }
20
- let(:searchable) { Searchable.new }
21
-
22
- before do
23
- # Redefine the options for multisearchable
24
- Searchable.multisearchable(multisearchable_options)
25
- end
26
-
27
- context "when searching against a single column" do
28
- let(:multisearchable_options) { {:against => :some_content} }
29
- let(:text) { "foo bar" }
30
- before do
31
- allow(searchable).to receive(:some_content) { text }
32
- document.valid?
33
- end
34
-
35
- describe '#content' do
36
- subject { super().content }
37
- it { is_expected.to eq(text) }
38
- end
39
- end
40
-
41
- context "when searching against multiple columns" do
42
- let(:multisearchable_options) { {:against => [:attr1, :attr2]} }
43
- before do
44
- allow(searchable).to receive(:attr1) { '1' }
45
- allow(searchable).to receive(:attr2) { '2' }
46
- document.valid?
47
- end
48
-
49
- describe '#content' do
50
- subject { super().content }
51
- it { is_expected.to eq("1 2") }
52
- end
53
- end
54
- end
55
- end
56
- end