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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- search_magic (0.0.8)
4
+ search_magic (0.0.9)
5
5
  mongoid (>= 2.0.0)
6
6
 
7
7
  GEM
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
- Finally, it should be noted that nesting of searchable documents is possible. (Currently, cyclic searches, where, for documents A and B, A searching on B which also searches on A should be avoided. Doing so is not prohibited, but will likely cause the environment to crash.) 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.
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 = searchable_fields.map do |field_name, options|
55
- if association = reflect_on_association(field_name)
56
- options[:as] ||= nil
57
- only = [options[:only]].flatten.compact
58
- except = [:_D_E_A_D_B_3_3_F_, options[:except]].flatten.compact
59
- associated = association.class_name.constantize.searchables
60
- wanted = associated.keys.grep(/^(?!.*?(#{except.join("|")})).*/).grep(/^#{only.join("|")}/)
61
- associated.select {|key, value| wanted.include?(key)}.map do |name, metadata|
62
- Metadata.new(:type => self, :through => lambda do |obj|
63
- value = obj.send(field_name)
64
- value.is_a?(Array) ? value.map {|item| metadata.through.call(item)} : metadata.through.call(value)
65
- end, :prefix => field_name.to_s.singularize.to_sym, :field_name => name, :relation_metadata => association, :options => metadata.options.merge(options))
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.flatten
69
+ end
71
70
 
72
- Hash[*fields.map {|metadata| [metadata.name, metadata]}.flatten]
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 :type, :through, :prefix, :field_name, :relation_metadata, :options
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 ||= [options[:skip_prefix].presence ? nil : (prefix.present? ? (options[:as] || prefix) : nil),
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 = self.through.call(obj)
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
- self.through.call(obj)
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
@@ -1,3 +1,3 @@
1
1
  module SearchMagic
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
data/lib/search_magic.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  module SearchMagic
2
+ require 'search_magic/breadcrumb'
3
+ require 'search_magic/stack_frame'
2
4
  require 'search_magic/metadata'
3
5
  require 'search_magic/full_text_search'
4
6
  end
@@ -0,0 +1,8 @@
1
+ class Graph1ModelA
2
+ include Mongoid::Document
3
+ include SearchMagic::FullTextSearch
4
+ field :foo
5
+ references_and_referenced_in_many :graph_1_model_bs
6
+ search_on :foo
7
+ search_on :graph_1_model_bs
8
+ end
@@ -0,0 +1,8 @@
1
+ class Graph1ModelB
2
+ include Mongoid::Document
3
+ include SearchMagic::FullTextSearch
4
+ field :bar
5
+ references_and_referenced_in_many :graph_1_model_as
6
+ search_on :bar
7
+ search_on :graph_1_model_as
8
+ end
@@ -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.8
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-03 00:00:00 -07:00
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