grn_mini 0.2.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8b9f025b3d3dfc38fd85b82b8552b9df10244dd8
4
- data.tar.gz: 2294e3e7af33ffd32d15253d01572bbeff84bbb3
3
+ metadata.gz: 954b7ebeb13d40913ed6022a6b96d972193b73ea
4
+ data.tar.gz: c64cf4de87e4cf59b172fb1b4d5c64d7f8f17e12
5
5
  SHA512:
6
- metadata.gz: 44faf36a48ca1245ddd3621955b998295a7e608e1f6ddb98229374391374cb18919c4883c0a3c0517fa4cee9eb9034a213e3a87ba271f3f4c2611f3454015c9b
7
- data.tar.gz: 68bd08647aa71e471072aec681a547821f06c111fcac909309545986f0898b9046d365fee677bc4334047772f844a286a673a39b738ff0317a2e8001160a619b
6
+ metadata.gz: 0406c079b5f1fac34c4f35de6e0ca59b1236df413b285ec28d529c054e1e08f1558f03712b24c37d2dba53f843e219db3ecc37e3d3ea33143faf4121c50b6fb1
7
+ data.tar.gz: 747fe7c71d88f786229ad7461639b9ff4de8cee0bc73e27aff73ce3301c98659311173517434b98b857b91bbbace9aabb084ee3900c968fd828bad8531d43af3
data/README.md CHANGED
@@ -52,6 +52,25 @@ end
52
52
  # Delete temporary database
53
53
  ```
54
54
 
55
+ ## Create Hash
56
+
57
+ ```ruby
58
+ require 'grn_mini'
59
+
60
+ hash = GrnMini::Hash.new("test.db")
61
+
62
+ # Add
63
+ hash["a"] = {text:"aaa", number:1}
64
+ hash["b"] = {text:"bbb", number:2}
65
+ hash["c"] = {text:"ccc", number:3}
66
+
67
+ # Read
68
+ hash["b"].text #=> "bbb"
69
+
70
+ # Write
71
+ hash["b"].text = "BBB"
72
+ ```
73
+
55
74
  ## Data Type
56
75
 
57
76
  ```ruby
data/lib/grn_mini.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "grn_mini/version"
2
2
  require "grn_mini/array"
3
+ require "grn_mini/hash"
3
4
  require "grn_mini/util"
4
5
 
5
6
  module GrnMini
@@ -0,0 +1,95 @@
1
+ require 'grn_mini/util'
2
+ require 'groonga'
3
+ require 'tmpdir'
4
+
5
+ module GrnMini
6
+ class Hash
7
+ attr_accessor :grn
8
+ include Enumerable
9
+
10
+ def self.tmpdb
11
+ Dir.mktmpdir do |dir|
12
+ # p dir
13
+ yield self.new(File.join(dir, "tmp.db"))
14
+ end
15
+ end
16
+
17
+ def initialize(path)
18
+ unless File.exist?(path)
19
+ Groonga::Database.create(path: path)
20
+ else
21
+ Groonga::Database.open(path)
22
+ end
23
+
24
+ @grn = Groonga["Hash"] || Groonga::Hash.create(name: "Hash", persistent: true)
25
+ @terms = Groonga["Terms"] || Groonga::PatriciaTrie.create(name: "Terms", key_normalize: true, default_tokenizer: "TokenBigramSplitSymbolAlphaDigit")
26
+ end
27
+
28
+ def add(key, values)
29
+ if @grn.empty?
30
+ values.each do |key, value|
31
+ column = key.to_s
32
+
33
+ # @todo Need define_index_column ?
34
+ if value.is_a?(Time)
35
+ @grn.define_column(column, "Time")
36
+ elsif value.is_a?(Float)
37
+ @grn.define_column(column, "Float")
38
+ elsif value.is_a?(Numeric)
39
+ @grn.define_column(column, "Int32")
40
+ else
41
+ @grn.define_column(column, "ShortText")
42
+ @terms.define_index_column("array_#{column}", @grn, source: "Hash.#{column}", with_position: true)
43
+ end
44
+ end
45
+ end
46
+
47
+ @grn.add(key, values)
48
+ end
49
+
50
+ def [](key)
51
+ @grn[key]
52
+ end
53
+
54
+ def []=(key, value)
55
+ add(key, value)
56
+ end
57
+
58
+ def select(query, options = {default_column: "text"})
59
+ @grn.select(query, options)
60
+ end
61
+
62
+ def size
63
+ @grn.size
64
+ end
65
+
66
+ alias length size
67
+
68
+ def empty?
69
+ size == 0
70
+ end
71
+
72
+ def each
73
+ @grn.each do |record|
74
+ yield record
75
+ end
76
+ end
77
+
78
+ def delete(id = nil, &block)
79
+ if block_given?
80
+ @grn.delete(&block)
81
+ else
82
+ raise IdIsGreaterThanZero if id == 0
83
+ @grn.delete(id)
84
+ end
85
+ end
86
+
87
+ def sort(keys, options = {})
88
+ @grn.sort(keys, options)
89
+ end
90
+
91
+ def group(key, options = {})
92
+ @grn.group(key, options)
93
+ end
94
+ end
95
+ end
@@ -1,3 +1,3 @@
1
1
  module GrnMini
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -15,7 +15,7 @@ module Input
15
15
 
16
16
  if File.file? filename
17
17
  next if ignore_file?(filename)
18
- array << {filename: filename, text: read_file(filename), timestamp: File.stat(filename).mtime, suffix: File.extname(filename).sub('.', ""), index: index } # index is dirty
18
+ array << {filename: filename, text: read_file(filename), timestamp: File.stat(filename).mtime, suffix: File.extname(filename).sub('.', "")}
19
19
  index += 1
20
20
  end
21
21
  end
@@ -61,7 +61,7 @@ class Search
61
61
  elements = []
62
62
 
63
63
  page_entries.each do |record|
64
- element = "<hr>\n<a href=\"/#{record.index}\">#{record.filename}</a>\n"
64
+ element = "<hr>\n<a href=\"/#{record.value.key.id}\">#{record.filename}</a>\n"
65
65
 
66
66
  snippet.execute(record.text).each do |segment|
67
67
  element += "<pre style=\"border:1px solid #bbb;\">#{segment}</pre>\n"
@@ -41,6 +41,7 @@ class TestGrnMiniArray < MiniTest::Unit::TestCase
41
41
  results = array.select("bb number:<10")
42
42
 
43
43
  assert_equal 1, results.size
44
+ assert_equal 2, results.first.key.id
44
45
  assert_equal "bbb", results.first.text
45
46
  assert_equal 2, results.first.number
46
47
  end
@@ -325,8 +326,8 @@ EOF
325
326
  record = results.first
326
327
  segments = snippet.execute(record.text)
327
328
  assert_equal 2, segments.size
328
- assert_match /\[1\] <<This>> is a <<pen>> pep pea pek pet./, segments[0]
329
- assert_match /\[2\] <<This>> is a <<pen>> pep pea pek pet./, segments[1]
329
+ assert_match /\[1\]<< This>> is a<< pen>> pep pea pek pet./, segments[0]
330
+ assert_match /\[2\]<< This>> is a<< pen>> pep pea pek pet./, segments[1]
330
331
  end
331
332
  end
332
333
 
@@ -344,7 +345,7 @@ EOF
344
345
  record = results.first
345
346
  segments = snippet.execute(record.text)
346
347
  assert_equal 1, segments.size
347
- assert_equal "&lt;html&gt;\n &lt;div&gt;<strong>This</strong> is a <strong>pen</strong> pep pea pek pet.&lt;/div&gt;\n&lt;/html&gt;\n", segments.first
348
+ assert_equal "&lt;html&gt;\n &lt;div&gt;<strong>This</strong> is a<strong> pen</strong> pep pea pek pet.&lt;/div&gt;\n&lt;/html&gt;\n", segments.first
348
349
  end
349
350
  end
350
351
 
@@ -0,0 +1,260 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestGrnMiniHash < MiniTest::Unit::TestCase
4
+ def test_initialize
5
+ Dir.mktmpdir do |dir|
6
+ hash = GrnMini::Hash.new(File.join(dir, "test.db"))
7
+ end
8
+ end
9
+
10
+ def test_add
11
+ GrnMini::Hash.tmpdb do |hash|
12
+ hash.add("aaa", text:"aaa", number:1)
13
+ assert_equal 1, hash.size
14
+
15
+ # alias []=
16
+ hash["bbb"] = {text:"bbb", number:2}
17
+ assert_equal 2, hash.size
18
+ end
19
+ end
20
+
21
+ def test_select
22
+ GrnMini::Hash.tmpdb do |hash|
23
+ hash["a"] = {text:"aaa", number:1}
24
+ hash["b"] = {text:"bbb", number:2}
25
+ hash["c"] = {text:"ccc", number:3}
26
+
27
+ results = hash.select("bb")
28
+
29
+ assert_equal 1, results.size
30
+ assert_equal "b", results.first.key.key
31
+ assert_equal "bbb", results.first.text
32
+ end
33
+ end
34
+
35
+ def test_select2
36
+ GrnMini::Hash.tmpdb do |hash|
37
+ hash["a"] = {text:"aaa", number:1}
38
+ hash["b"] = {text:"bbb", number:2}
39
+ hash["c"] = {text:"bbb", number:20}
40
+ hash["d"] = {text:"ccc", number:3}
41
+
42
+ results = hash.select("bb number:<10")
43
+
44
+ assert_equal 1, results.size
45
+ assert_equal "b", results.first.key.key
46
+ assert_equal "bbb", results.first.text
47
+ assert_equal 2, results.first.number
48
+ end
49
+ end
50
+
51
+ def test_size
52
+ GrnMini::Hash.tmpdb do |hash|
53
+ assert_equal 0, hash.size
54
+ assert_equal 0, hash.length
55
+
56
+ hash["a"] = {text:"aaa", number:1}
57
+ hash["b"] = {text:"bbb", number:2}
58
+ assert_equal 2, hash.size
59
+ assert_equal 2, hash.length
60
+ end
61
+ end
62
+
63
+ def test_empty?
64
+ GrnMini::Hash.tmpdb do |hash|
65
+ assert_equal true, hash.empty?
66
+
67
+ hash["a"] = {text:"aaa", number:1}
68
+ assert_equal false, hash.empty?
69
+ end
70
+ end
71
+
72
+ def test_each
73
+ GrnMini::Hash.tmpdb do |hash|
74
+ hash["c"] = {text:"ccc", number:3}
75
+ hash["a"] = {text:"aaa", number:1}
76
+ hash["b"] = {text:"bbb", number:2}
77
+
78
+ total = 0
79
+
80
+ hash.each do |v|
81
+ total += v.number
82
+ end
83
+
84
+ assert_equal 6, total
85
+ end
86
+ end
87
+
88
+ def test_read_by_key
89
+ GrnMini::Hash.tmpdb do |hash|
90
+ hash["a"] = {text:"aaa", number:1}
91
+ hash["b"] = {text:"bbb", number:2}
92
+ hash["c"] = {text:"ccc", number:3}
93
+
94
+ assert_equal nil, hash["not found"]
95
+ assert_equal "aaa", hash["a"].text
96
+ assert_equal "bbb", hash["b"].text
97
+ assert_equal "ccc", hash["c"].text
98
+ end
99
+ end
100
+
101
+ def test_write_by_key
102
+ GrnMini::Hash.tmpdb do |hash|
103
+ hash["a"] = {text:"aaa", number:1}
104
+ hash["b"] = {text:"bbb", number:2}
105
+ hash["c"] = {text:"ccc", number:3}
106
+
107
+ assert_equal "bbb", hash["b"].text
108
+ assert_equal 2, hash["b"].number
109
+
110
+ hash["b"].text = "BBB"
111
+ hash["b"].number = 22
112
+
113
+ assert_equal "BBB", hash["b"].text
114
+ assert_equal 22, hash["b"].number
115
+ end
116
+ end
117
+
118
+ def test_delete_by_id
119
+ GrnMini::Hash.tmpdb do |hash|
120
+ hash["a"] = {text:"aaa", number:1}
121
+ hash["b"] = {text:"bbb", number:2}
122
+ hash["c"] = {text:"ccc", number:3}
123
+
124
+ # Delete from key
125
+ assert_equal 3, hash.size
126
+ assert_equal 2, hash["b"].number
127
+
128
+ hash.delete("b")
129
+
130
+ assert_equal 2, hash.size
131
+ assert_nil hash["b"]
132
+ end
133
+ end
134
+
135
+ def test_delete_by_block
136
+ GrnMini::Hash.tmpdb do |hash|
137
+ hash["a"] = {text:"aaa", number:1}
138
+ hash["b"] = {text:"bbb", number:2}
139
+ hash["c"] = {text:"ccc", number:3}
140
+
141
+ hash.delete do |record|
142
+ record.number >= 2
143
+ end
144
+
145
+ assert_equal 1, hash.size
146
+ assert_equal "aaa", hash.first.text
147
+ assert_equal 1, hash.first.number
148
+ end
149
+ end
150
+
151
+ def test_float_column
152
+ GrnMini::Hash.tmpdb do |hash|
153
+ hash["a"] = {text:"aaaa", float: 1.5}
154
+ hash["b"] = {text:"bbbb", float: 2.5}
155
+ hash["c"] = {text:"cccc", float: 3.5}
156
+
157
+ assert_equal 2.5, hash["b"].float
158
+
159
+ results = hash.select("float:>2.6")
160
+ assert_equal 3.5, results.first.float
161
+ end
162
+ end
163
+
164
+ def test_time_column
165
+ GrnMini::Hash.tmpdb do |hash|
166
+ hash["a"] = {text:"aaaa", timestamp: Time.new(2013)} # 2013-01-01
167
+ hash["b"] = {text:"bbbb", timestamp: Time.new(2014)} # 2014-01-01
168
+ hash["c"] = {text:"cccc", timestamp: Time.new(2015)} # 2015-01-01
169
+
170
+ assert_equal Time.new(2014), hash["b"].timestamp
171
+
172
+ results = hash.select("timestamp:<=#{Time.new(2013,12).to_i}")
173
+ assert_equal 1, results.size
174
+ assert_equal Time.new(2013), results.first.timestamp
175
+ end
176
+ end
177
+
178
+ def test_record_attributes
179
+ GrnMini::Hash.tmpdb do |hash|
180
+ hash["a"] = {text:"aaaa", int: 1}
181
+ hash["b"] = {text:"bbbb", int: 2}
182
+ hash["c"] = {text:"cccc", int: 3}
183
+
184
+ assert_equal({"_id"=>1, "_key"=>"a", "int"=>1, "text"=>"aaaa"}, hash["a"].attributes)
185
+ assert_equal({"_id"=>2, "_key"=>"b", "int"=>2, "text"=>"bbbb"}, hash["b"].attributes)
186
+ assert_equal({"_id"=>3, "_key"=>"c", "int"=>3, "text"=>"cccc"}, hash["c"].attributes)
187
+ end
188
+ end
189
+
190
+ def test_assign_long_text_to_short_text
191
+ GrnMini::Hash.tmpdb do |hash|
192
+ hash["a"] = {filename:"a.txt"}
193
+ hash["b"] = {filename:"a"*4095 + ".txt" } # Over 4095 byte (ShortText limit)
194
+
195
+ results = hash.select("txt", default_column: "filename")
196
+ assert_equal 2, results.size
197
+ end
198
+ end
199
+
200
+ def test_grn_object
201
+ GrnMini::Hash.tmpdb do |hash|
202
+ hash["a"] = {text: "aaaa", filename:"a.txt", int: 1, float: 1.5, time: Time.at(2001)}
203
+
204
+ raw = hash.grn
205
+
206
+ assert_equal true, raw.have_column?("filename")
207
+ assert_equal true, raw.have_column?("int")
208
+ assert_equal true, raw.have_column?("float")
209
+ assert_equal true, raw.have_column?("time")
210
+ assert_equal false, raw.have_column?("timeee")
211
+
212
+ assert_equal "ShortText", raw.column("text").range.name
213
+ assert_equal "ShortText", raw.column("filename").range.name
214
+ assert_equal "Int32" , raw.column("int").range.name
215
+ assert_equal "Float" , raw.column("float").range.name
216
+ assert_equal "Time" , raw.column("time").range.name
217
+
218
+ assert_equal true, raw.support_key? # GrnMini::Array is false
219
+ assert_equal false, raw.support_sub_records?
220
+ end
221
+ end
222
+
223
+ def test_sort
224
+ GrnMini::Hash.tmpdb do |hash|
225
+ hash["a"] = {name:"Tanaka", age: 11, height: 162.5}
226
+ hash["b"] = {name:"Suzuki", age: 31, height: 170.0}
227
+ hash["c"] = {name:"Hayashi", age: 21, height: 175.4}
228
+ hash["d"] = {name:"Suzuki", age: 5, height: 110.0}
229
+
230
+ sorted_by_age = hash.sort(["age"])
231
+ sorted_array = sorted_by_age.map {|r| {name: r.name, age: r.age}}
232
+ assert_equal [{:name=>"Suzuki", :age=>5},
233
+ {:name=>"Tanaka", :age=>11},
234
+ {:name=>"Hayashi", :age=>21},
235
+ {:name=>"Suzuki", :age=>31}], sorted_array
236
+
237
+ sorted_by_combination = hash.sort([{key: "name", order: :ascending},
238
+ {key: "age" , order: :descending}])
239
+ sorted_array = sorted_by_combination.map {|r| {name: r.name, age: r.age}}
240
+ assert_equal [{:name=>"Hayashi", :age=>21},
241
+ {:name=>"Suzuki", :age=>31},
242
+ {:name=>"Suzuki", :age=>5},
243
+ {:name=>"Tanaka", :age=>11}], sorted_array
244
+ end
245
+ end
246
+
247
+ def test_group_from_hash
248
+ GrnMini::Hash.tmpdb do |hash|
249
+ hash["a"] = {text:"aaaa.txt", suffix:"txt", type:1}
250
+ hash["b"] = {text:"aaaa.doc", suffix:"doc", type:2}
251
+ hash["c"] = {text:"aabb.txt", suffix:"txt", type:2}
252
+
253
+ groups = GrnMini::Util::group_with_sort(hash, "suffix")
254
+
255
+ assert_equal 2, groups.size
256
+ assert_equal ["txt", 2], [groups[0].key, groups[0].n_sub_records]
257
+ assert_equal ["doc", 1], [groups[1].key, groups[1].n_sub_records]
258
+ end
259
+ end
260
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grn_mini
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ongaeshi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-07 00:00:00.000000000 Z
11
+ date: 2014-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -85,12 +85,14 @@ files:
85
85
  - grn_mini.gemspec
86
86
  - lib/grn_mini.rb
87
87
  - lib/grn_mini/array.rb
88
+ - lib/grn_mini/hash.rb
88
89
  - lib/grn_mini/util.rb
89
90
  - lib/grn_mini/version.rb
90
91
  - sample/mini-directory-search.rb
91
92
  - test/minitest_helper.rb
92
93
  - test/test_grn_mini.rb
93
94
  - test/test_grn_mini_array.rb
95
+ - test/test_grn_mini_hash.rb
94
96
  homepage: ''
95
97
  licenses:
96
98
  - MIT
@@ -119,3 +121,4 @@ test_files:
119
121
  - test/minitest_helper.rb
120
122
  - test/test_grn_mini.rb
121
123
  - test/test_grn_mini_array.rb
124
+ - test/test_grn_mini_hash.rb