komainu 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -14,13 +14,18 @@ require "komainu"
14
14
  require "ostruct"
15
15
 
16
16
  item1 = OpenStruct.new
17
- item1.text = "hello"
17
+ item1.text = "You are a smelly pirate hooker."
18
+
18
19
  item2 = OpenStruct.new
19
- item2.text = "world"
20
+ item2.text = "You look like a blueberry."
21
+
22
+ item3 = OpenStruct.new
23
+ item3.text = "Why don't you go back to your home on Whore Island?"
24
+
20
25
  searchables = [item1, item2]
21
- Komainu.search("world", searchables)
26
+ Komainu.search("blue", searchables)
22
27
 
23
- #=> {:suggestion=>nil, :items=>["world"]}
28
+ #=> {:suggestion=>nil, :items=>["You look like a blueberry."]}
24
29
  ```
25
30
 
26
31
  ### Suggestions
@@ -15,13 +15,18 @@ require "komainu"
15
15
  require "ostruct"
16
16
 
17
17
  item1 = OpenStruct.new
18
- item1.text = "hello"
18
+ item1.text = "You are a smelly pirate hooker."
19
+
19
20
  item2 = OpenStruct.new
20
- item2.text = "world"
21
+ item2.text = "You look like a blueberry."
22
+
23
+ item3 = OpenStruct.new
24
+ item3.text = "Why don't you go back to your home on Whore Island?"
25
+
21
26
  searchables = [item1, item2]
22
- Komainu.search("world", searchables)
27
+ Komainu.search("blue", searchables)
23
28
 
24
- #=> {:suggestion=>nil, :items=>["world"]}
29
+ #=> {:suggestion=>nil, :items=>["You look like a blueberry."]}
25
30
  :end:
26
31
  ```
27
32
 
@@ -7,9 +7,9 @@ Gem::Specification.new do |s|
7
7
  s.version = Komainu::VERSION
8
8
  s.authors = ["Andrew Vos"]
9
9
  s.email = ["andrew.vos@gmail.com"]
10
- s.homepage = ""
11
- s.summary = %q{}
12
- s.description = %q{}
10
+ s.homepage = "https://github.com/AndrewVos/komainu"
11
+ s.summary = %q{Simple text search}
12
+ s.description = %q{Simple text search using a mixture of basic string search and Levenshtein Distance}
13
13
 
14
14
  s.rubyforge_project = "komainu"
15
15
 
@@ -1,7 +1,7 @@
1
1
  require "komainu/trie_node"
2
2
 
3
3
  module Komainu
4
- class Levenshtein
4
+ class CalculatesLevenshteinDistance
5
5
  def initialize(words)
6
6
  @trie = TrieNode.new
7
7
  words.each do |word|
@@ -0,0 +1,9 @@
1
+ module Komainu
2
+ class Match
3
+ attr_reader :index, :text
4
+ def initialize index, text
5
+ @index = index
6
+ @text = text
7
+ end
8
+ end
9
+ end
@@ -1,7 +1,16 @@
1
- require "komainu/levenshtein"
1
+ require "komainu/calculates_levenshtein_distance"
2
2
  require "komainu/search_results"
3
+ require "komainu/match"
3
4
 
4
5
  module Komainu
6
+ class SearchResult
7
+ attr_reader :object, :matches
8
+ def initialize object, matches
9
+ @object = object
10
+ @matches = matches
11
+ end
12
+ end
13
+
5
14
  class SearchesText
6
15
  def initialize data_to_search
7
16
  @data_to_search = data_to_search
@@ -10,10 +19,9 @@ module Komainu
10
19
  def search query
11
20
  results = SearchResults.new
12
21
  @data_to_search.each do |searchable|
13
- if text_includes_string(searchable.text, query)
14
- results.items << searchable
15
- elsif text_includes_words_from_string(searchable.text, query)
16
- results.items << searchable
22
+ matches = find_matches(searchable.text, query)
23
+ if matches.any?
24
+ results.items << SearchResult.new(searchable, matches)
17
25
  end
18
26
  end
19
27
 
@@ -25,7 +33,7 @@ module Komainu
25
33
 
26
34
  def calculate_suggestion(query)
27
35
  words = split_into_words(@data_to_search.map { |searchable| searchable.text }.join(" "))
28
- levenshtein = Levenshtein.new(words)
36
+ levenshtein = CalculatesLevenshteinDistance.new(words)
29
37
 
30
38
  suggestion = split_into_words(query).map do |word|
31
39
  matches = levenshtein.search(word, 2)
@@ -49,14 +57,18 @@ module Komainu
49
57
  string.scan(/\b\w+\b/)
50
58
  end
51
59
 
52
- def text_includes_string text, string
53
- text.downcase.include? string.downcase
54
- end
55
-
56
- def text_includes_words_from_string text, string
57
- string.split(" ").any? do |word|
58
- text_includes_string(text, word)
59
- end
60
+ def find_matches text, string
61
+ text = text.downcase
62
+ matches = []
63
+ string.split(" ").each { |word|
64
+ word = word.downcase
65
+ offset = 0
66
+ while matched_index = text.index(word, offset)
67
+ matches << Match.new(matched_index, word)
68
+ offset += word.length
69
+ end
70
+ }
71
+ matches
60
72
  end
61
73
  end
62
74
  end
@@ -1,3 +1,3 @@
1
1
  module Komainu
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -1,10 +1,10 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
- require "komainu/levenshtein"
2
+ require "komainu/calculates_levenshtein_distance"
3
3
 
4
4
  module Komainu
5
- describe Levenshtein do
5
+ describe CalculatesLevenshteinDistance do
6
6
  it "finds words with a distance less the maximum distance" do
7
- levenshtein = Levenshtein.new(["hello", "there", "good", "sirs"])
7
+ levenshtein = CalculatesLevenshteinDistance.new(["hello", "there", "good", "sirs"])
8
8
  levenshtein.search("hell", 14).must_equal({
9
9
  "hello" => 1,
10
10
  "there" => 3,
@@ -6,31 +6,27 @@ module Komainu
6
6
  subject { SearchesText.new(data_to_search) }
7
7
 
8
8
  let :data_to_search do
9
- item1 = OpenStruct.new
10
- item1.name = :item1
11
- item1.text = "This is some text."
12
- item2 = OpenStruct.new
13
- item2.name = :item2
14
- item2.text = "Batman has no parents"
15
- [item1, item2]
9
+ @item1 = OpenStruct.new({:text => "This is some text."})
10
+ @item2 = OpenStruct.new({:text => "Batman has no parents"})
11
+ [@item1, @item2]
16
12
  end
17
13
 
18
14
  it "finds exact matches" do
19
15
  result = subject.search("Batman has")
20
16
  result.items.size.must_equal 1
21
- result.items.first.name.must_equal :item2
17
+ result.items.first.object.must_equal @item2
22
18
  end
23
19
 
24
20
  it "finds matches in any case" do
25
21
  result = subject.search("BATMAN has")
26
22
  result.items.size.must_equal 1
27
- result.items.first.name.must_equal :item2
23
+ result.items.first.object.must_equal @item2
28
24
  end
29
25
 
30
26
  it "finds matches if the text is not in order" do
31
27
  result = subject.search("has batman")
32
28
  result.items.size.must_equal 1
33
- result.items.first.name.must_equal :item2
29
+ result.items.first.object.must_equal @item2
34
30
  end
35
31
 
36
32
  it "suggests an alternate query" do
@@ -49,5 +45,18 @@ module Komainu
49
45
  result = SearchesText.new([item]).search("hell")
50
46
  result.suggestion.must_equal "hellp"
51
47
  end
48
+
49
+ it "knows where the matches were" do
50
+ item = OpenStruct.new
51
+ item.text = "Derp herp"
52
+
53
+ result = SearchesText.new([item]).search("derp herp")
54
+
55
+ result.items.first.matches[0].text.must_equal "derp"
56
+ result.items.first.matches[0].index.must_equal 0
57
+
58
+ result.items.first.matches[2].text.must_equal "herp"
59
+ result.items.first.matches[2].index.must_equal 5
60
+ end
52
61
  end
53
62
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: komainu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-25 00:00:00.000000000Z
12
+ date: 2011-12-01 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
16
- requirement: &70133062670220 !ruby/object:Gem::Requirement
16
+ requirement: &70258233968580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70133062670220
24
+ version_requirements: *70258233968580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70133062669200 !ruby/object:Gem::Requirement
27
+ requirement: &70258233967340 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70133062669200
35
+ version_requirements: *70258233967340
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: docu
38
- requirement: &70133062668160 !ruby/object:Gem::Requirement
38
+ requirement: &70258233966460 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,8 +43,9 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70133062668160
47
- description: ''
46
+ version_requirements: *70258233966460
47
+ description: Simple text search using a mixture of basic string search and Levenshtein
48
+ Distance
48
49
  email:
49
50
  - andrew.vos@gmail.com
50
51
  executables: []
@@ -60,18 +61,19 @@ files:
60
61
  - Rakefile
61
62
  - komainu.gemspec
62
63
  - lib/komainu.rb
64
+ - lib/komainu/calculates_levenshtein_distance.rb
63
65
  - lib/komainu/komainu.rb
64
- - lib/komainu/levenshtein.rb
66
+ - lib/komainu/match.rb
65
67
  - lib/komainu/search_results.rb
66
68
  - lib/komainu/searches_text.rb
67
69
  - lib/komainu/trie_node.rb
68
70
  - lib/komainu/version.rb
71
+ - spec/komainu/calculates_levenshtein_distance_spec.rb
69
72
  - spec/komainu/komainu_spec.rb
70
- - spec/komainu/levenshtein_spec.rb
71
73
  - spec/komainu/searches_text_spec.rb
72
74
  - spec/komainu/trie_node_spec.rb
73
75
  - spec/spec_helper.rb
74
- homepage: ''
76
+ homepage: https://github.com/AndrewVos/komainu
75
77
  licenses: []
76
78
  post_install_message:
77
79
  rdoc_options: []
@@ -94,10 +96,10 @@ rubyforge_project: komainu
94
96
  rubygems_version: 1.8.10
95
97
  signing_key:
96
98
  specification_version: 3
97
- summary: ''
99
+ summary: Simple text search
98
100
  test_files:
101
+ - spec/komainu/calculates_levenshtein_distance_spec.rb
99
102
  - spec/komainu/komainu_spec.rb
100
- - spec/komainu/levenshtein_spec.rb
101
103
  - spec/komainu/searches_text_spec.rb
102
104
  - spec/komainu/trie_node_spec.rb
103
105
  - spec/spec_helper.rb