search_magic 0.0.8 → 0.0.9
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/Gemfile.lock +1 -1
- data/README.textile +22 -2
- data/lib/search_magic/breadcrumb.rb +20 -0
- data/lib/search_magic/full_text_search.rb +15 -16
- data/lib/search_magic/metadata.rb +11 -6
- data/lib/search_magic/stack_frame.rb +28 -0
- data/lib/search_magic/version.rb +1 -1
- data/lib/search_magic.rb +2 -0
- data/spec/models/graph_1_model_a.rb +8 -0
- data/spec/models/graph_1_model_b.rb +8 -0
- data/spec/unit/search_magic/graph_searches_spec.rb +19 -0
- metadata +10 -2
data/Gemfile.lock
CHANGED
data/README.textile
CHANGED
@@ -86,7 +86,27 @@ end
|
|
86
86
|
|
87
87
|
p. Now all entries within *:searchable_values* for *:tags* will retain meaningful punctuation. The previous example is interesting for another reason: embedded arrays are handled specially. Specifically, the selector for an embedded array will be singularized. In the case of the previous example, this would result in a selector of "tag".
|
88
88
|
|
89
|
-
|
89
|
+
Two documents may search on each other's fields; doing so will cause each document to only search upon those fields stemming from itself once. Given the following example, _Foo_ would be able to search on @[:name, :bar_value]@, while _Bar_ would be able to search on @[:value, :foo_name]@.
|
90
|
+
|
91
|
+
bc.. class Foo
|
92
|
+
include Mongoid::Document
|
93
|
+
include SearchMagic::FullTextSearch
|
94
|
+
field :name
|
95
|
+
references_many :bars
|
96
|
+
search_on :name
|
97
|
+
search_on :bars
|
98
|
+
end
|
99
|
+
|
100
|
+
class Bar
|
101
|
+
include Mongoid::Document
|
102
|
+
include SearchMagic::FullTextSearch
|
103
|
+
field :value
|
104
|
+
referenced_in :foo
|
105
|
+
search_on :value
|
106
|
+
search_on :foo
|
107
|
+
end
|
108
|
+
|
109
|
+
Finally, it should be noted that nesting of searchable documents is possible. If a given document searches on an association with another document which, in and of itself, searches on a third document, the first automatically has access to the third document's searchable fields.
|
90
110
|
|
91
111
|
bc.. class Part
|
92
112
|
include Mongoid::Document
|
@@ -119,7 +139,7 @@ class PartCategory
|
|
119
139
|
search_on :name
|
120
140
|
end
|
121
141
|
|
122
|
-
p. *PartNumber* will be able to search on both _:number_ and _:category_name_. *Part*, on the other hand, will absorb all of the searchable fields of PartNumber, including its associations. So, it can be searched on _:serial_, _:number_, and _:category_name_
|
142
|
+
p. *PartNumber* will be able to search on both _:number_ and _:category_name_. *Part*, on the other hand, will absorb all of the searchable fields of PartNumber, including its associations. So, it can be searched on _:serial_, _:number_, and _:category_name_.
|
123
143
|
|
124
144
|
h3. :search_for
|
125
145
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SearchMagic
|
2
|
+
class Breadcrumb
|
3
|
+
attr_accessor :field_name, :options
|
4
|
+
|
5
|
+
def initialize(field_name, options)
|
6
|
+
self.field_name = field_name
|
7
|
+
self.options = options
|
8
|
+
self.options[:except] = Array.wrap(self.options[:except]).compact
|
9
|
+
self.options[:only] = Array.wrap(self.options[:only]).compact
|
10
|
+
end
|
11
|
+
|
12
|
+
def term
|
13
|
+
@term ||= options[:skip_prefix].presence ? nil : (options[:as] || field_name.to_s.pluralize.singularize)
|
14
|
+
end
|
15
|
+
|
16
|
+
def clone
|
17
|
+
Breadcrumb.new(field_name, options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -51,25 +51,24 @@ module SearchMagic
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def create_searchables
|
54
|
-
fields =
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
54
|
+
stack, visited, fields = [StackFrame.new(self)], {}, []
|
55
|
+
until stack.empty?
|
56
|
+
current = stack.shift
|
57
|
+
unless visited.has_key?(current.type)
|
58
|
+
visited[current.type] = true
|
59
|
+
current.type.searchable_fields.each do |field_name, options|
|
60
|
+
next unless current.wants_field?(field_name)
|
61
|
+
path = current.path.clone + [Breadcrumb.new(field_name, options)]
|
62
|
+
if association = current.type.reflect_on_association(field_name)
|
63
|
+
stack << StackFrame.new(association.class_name.constantize, path)
|
64
|
+
else
|
65
|
+
fields << Metadata.new(:origin_type => current.type, :through => path, :options => options)
|
66
|
+
end
|
66
67
|
end
|
67
|
-
else
|
68
|
-
Metadata.new(:type => self, :through => lambda {|obj| obj.send(field_name) }, :field_name => field_name.to_s.pluralize.singularize.to_sym, :options => options)
|
69
68
|
end
|
70
|
-
end
|
69
|
+
end
|
71
70
|
|
72
|
-
|
71
|
+
fields.index_by(&:name)
|
73
72
|
end
|
74
73
|
end
|
75
74
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module SearchMagic
|
2
2
|
class Metadata
|
3
|
-
attr_accessor :
|
4
|
-
|
3
|
+
attr_accessor :origin_type, :through, :options
|
4
|
+
|
5
5
|
def initialize(attributes = {})
|
6
6
|
attributes.each do |key, value|
|
7
7
|
send(:"#{key}=", value)
|
@@ -9,23 +9,28 @@ module SearchMagic
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def name
|
12
|
-
@name ||=
|
13
|
-
prefix.present? ? field_name : (options[:as] || field_name)].compact.join("_").to_sym
|
12
|
+
@name ||= through.map(&:term).compact.join("_").to_sym
|
14
13
|
end
|
15
14
|
|
16
15
|
def value_for(obj, keep_punctuation)
|
17
|
-
v =
|
16
|
+
v = get_value(obj)
|
18
17
|
v = v.is_a?(Array) ? v.join(" ") : v.to_s
|
19
18
|
v = v.gsub(/[[:punct:]]/, ' ') unless keep_punctuation
|
20
19
|
v
|
21
20
|
end
|
22
21
|
|
23
22
|
def arrangeable_value_for(obj)
|
24
|
-
|
23
|
+
get_value(obj)
|
25
24
|
end
|
26
25
|
|
27
26
|
def searchable_value_for(obj)
|
28
27
|
value_for(obj, options[:keep_punctuation]).downcase.split.map {|word| [name, word].join(":")}
|
29
28
|
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def get_value(obj)
|
33
|
+
self.through.map(&:field_name).inject(obj) {|memo, method| memo.is_a?(Array) ? memo.map{|o| o.send(method)} : memo.send(method)}
|
34
|
+
end
|
30
35
|
end
|
31
36
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SearchMagic
|
2
|
+
class StackFrame
|
3
|
+
attr_accessor :type, :path
|
4
|
+
|
5
|
+
def initialize(type, path = [])
|
6
|
+
self.type = type
|
7
|
+
self.path = path
|
8
|
+
end
|
9
|
+
|
10
|
+
def wants_field?(field_name)
|
11
|
+
!field_excluded?(field_name) && field_included?(field_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def field_included?(field_name)
|
17
|
+
options[:only].blank? || options[:only].include?(field_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def field_excluded?(field_name)
|
21
|
+
options[:except].present? && options[:except].include?(field_name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def options
|
25
|
+
@options ||= (path.last.try(:options) || {})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/search_magic/version.rb
CHANGED
data/lib/search_magic.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SearchMagic::FullTextSearch do
|
4
|
+
context "when given two models which search on each other" do
|
5
|
+
describe "calculating searchables from the first model" do
|
6
|
+
subject { Graph1ModelA }
|
7
|
+
it("should not raise an error") { expect { subject.searchables }.to_not raise_error }
|
8
|
+
its("searchables.keys") { should include(:foo, :graph_1_model_b_bar) }
|
9
|
+
its("searchables.keys") { should_not include(:graph_1_model_b_graph_1_model_a, :graph_1_model_b_graph_1_model_a_foo) }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "calculating searchables from the second model" do
|
13
|
+
subject { Graph1ModelB }
|
14
|
+
it("should not raise an error") { expect { subject.searchables }.to_not raise_error }
|
15
|
+
its("searchables.keys") { should include(:bar, :graph_1_model_a_foo) }
|
16
|
+
its("searchables.keys") { should_not include(:graph_1_model_a_graph_1_model_b, :graph_1_model_a_graph_1_model_b_bar) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: search_magic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.9
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Joshua Bowers
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-04-
|
13
|
+
date: 2011-04-05 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -73,8 +73,10 @@ files:
|
|
73
73
|
- README.textile
|
74
74
|
- Rakefile
|
75
75
|
- lib/search_magic.rb
|
76
|
+
- lib/search_magic/breadcrumb.rb
|
76
77
|
- lib/search_magic/full_text_search.rb
|
77
78
|
- lib/search_magic/metadata.rb
|
79
|
+
- lib/search_magic/stack_frame.rb
|
78
80
|
- lib/search_magic/version.rb
|
79
81
|
- search_magic.gemspec
|
80
82
|
- spec/models/absolutely_not_searchable.rb
|
@@ -82,6 +84,8 @@ files:
|
|
82
84
|
- spec/models/asset.rb
|
83
85
|
- spec/models/developer.rb
|
84
86
|
- spec/models/game.rb
|
87
|
+
- spec/models/graph_1_model_a.rb
|
88
|
+
- spec/models/graph_1_model_b.rb
|
85
89
|
- spec/models/is_searchable.rb
|
86
90
|
- spec/models/no_searchables.rb
|
87
91
|
- spec/models/part.rb
|
@@ -94,6 +98,7 @@ files:
|
|
94
98
|
- spec/unit/search_magic/arrangements_spec.rb
|
95
99
|
- spec/unit/search_magic/associations_spec.rb
|
96
100
|
- spec/unit/search_magic/fields_spec.rb
|
101
|
+
- spec/unit/search_magic/graph_searches_spec.rb
|
97
102
|
- spec/unit/search_magic/model_updates_spec.rb
|
98
103
|
has_rdoc: true
|
99
104
|
homepage: http://github.com/joshuabowers/search_magic
|
@@ -129,6 +134,8 @@ test_files:
|
|
129
134
|
- spec/models/asset.rb
|
130
135
|
- spec/models/developer.rb
|
131
136
|
- spec/models/game.rb
|
137
|
+
- spec/models/graph_1_model_a.rb
|
138
|
+
- spec/models/graph_1_model_b.rb
|
132
139
|
- spec/models/is_searchable.rb
|
133
140
|
- spec/models/no_searchables.rb
|
134
141
|
- spec/models/part.rb
|
@@ -141,4 +148,5 @@ test_files:
|
|
141
148
|
- spec/unit/search_magic/arrangements_spec.rb
|
142
149
|
- spec/unit/search_magic/associations_spec.rb
|
143
150
|
- spec/unit/search_magic/fields_spec.rb
|
151
|
+
- spec/unit/search_magic/graph_searches_spec.rb
|
144
152
|
- spec/unit/search_magic/model_updates_spec.rb
|