traildb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: db7de0236d2beb6228f974aaabd1534a1a57949e
4
+ data.tar.gz: 585c4d56fd4fb987e6d1d87f0cd5c0c1b860410d
5
+ SHA512:
6
+ metadata.gz: 5650746b5d2484faf595a5562defb0c675eeb7de6ae41d52230432cf43abd122b2ef02df3ff4df2958b6daea8713e4538e10eb5935649e33ad3e8771566a67f9
7
+ data.tar.gz: 5030283d3ac22d8ffbca26765a344d8f3e8e9f8711cb36f2a6ed856e19012d482af8fed4436be41e2de2fc414e18d40925c47a0bda40b61aeccf92ab8db9bfcb
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /*.tdb
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in traildb.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Ryosuke IWANAGA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Traildb
2
+
3
+ Operate TrailDB from Ruby code using this gem.
4
+
5
+ http://traildb.io/
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'traildb'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install traildb
22
+
23
+ ## Usage
24
+
25
+ ```ruby
26
+ require 'traildb'
27
+
28
+ cookie = '12345678-1234-5678-1234-567812345678'
29
+ cons = Traildb::TrailDBConstructor.new('foo.tdb', ['field1', 'field2'])
30
+ cons.add(cookie, 123, ['a'])
31
+ cons.add(cookie, 124, ['b', 'c'])
32
+ tdb = cons.finalize
33
+
34
+ tdb.trails.each do |cookie, trail|
35
+ trail.each do |event|
36
+ puts "#{cookie} #{event}"
37
+ end
38
+ end
39
+
40
+ #=> 12345678-1234-5678-1234-567812345678 #<struct time=123, field1="a", field2="">
41
+ #=> 12345678-1234-5678-1234-567812345678 #<struct time=124, field1="b", field2="c">
42
+ ```
43
+
44
+ ## Development
45
+
46
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
47
+
48
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
49
+
50
+ ## Contributing
51
+
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/riywo/traildb.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ t.options = '-v'
9
+ end
10
+
11
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "traildb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,18 @@
1
+ require 'traildb'
2
+ require 'securerandom'
3
+
4
+ cons = Traildb::TrailDBConstructor.new('tiny', ['username', 'action'])
5
+
6
+ 3.times.each do |i|
7
+ uuid = SecureRandom.uuid
8
+ username = 'user%d' % i
9
+ ['open', 'save', 'close'].each_with_index do |action, day|
10
+ cons.add(uuid, Time.new(2016, i + 1, day + 1), [username, action])
11
+ end
12
+ end
13
+
14
+ cons.finalize
15
+
16
+ Traildb::TrailDB.new('tiny').trails.each do |uuid, trail|
17
+ puts uuid, trail.to_a
18
+ end
@@ -0,0 +1,26 @@
1
+ require 'traildb'
2
+
3
+ SESSION_LIMIT = 30 * 60
4
+
5
+ def sessions(tdb)
6
+ tdb.trails(only_timestamp: true).each_with_index do |(uuid, trail), i|
7
+ trail = trail.to_enum
8
+ prev_time = trail.next
9
+ num_events = 1
10
+ num_sessions = 1
11
+ trail.each do |timestamp|
12
+ if timestamp - prev_time > SESSION_LIMIT
13
+ num_sessions += 1
14
+ end
15
+ prev_time = timestamp
16
+ num_events += 1
17
+ end
18
+ puts 'Trail[%d] Number of Sessions: %d Number of Events: %d' % [i, num_sessions, num_events]
19
+ end
20
+ end
21
+
22
+ if ARGV.size < 1
23
+ puts 'Usage: tutorial_wikipedia_sessions <wikipedia-history.tdb>'
24
+ else
25
+ sessions(Traildb::TrailDB.new(ARGV[0]))
26
+ end
@@ -0,0 +1,3 @@
1
+ module Traildb
2
+ VERSION = "0.1.0"
3
+ end
data/lib/traildb.rb ADDED
@@ -0,0 +1,435 @@
1
+ require "traildb/version"
2
+
3
+ require "ffi"
4
+
5
+ module Traildb
6
+ extend FFI::Library
7
+ ffi_lib "traildb"
8
+
9
+ typedef :pointer, :tdb
10
+ typedef :pointer, :tdb_cons
11
+ typedef :uint32, :tdb_field
12
+ typedef :uint64, :tdb_val
13
+ typedef :uint64, :tdb_item
14
+ typedef :pointer, :tdb_cursor
15
+ typedef :int, :tdb_error
16
+ typedef :pointer, :tdb_event_filter
17
+
18
+ class TdbEvent < FFI::Struct
19
+ layout(
20
+ :timestamp, :uint64,
21
+ :num_items, :uint64,
22
+ :items, [:tdb_item, 0],
23
+ )
24
+
25
+ def tdb_items(valuefun = nil)
26
+ address = pointer + offset_of(:items)
27
+ items = FFI::Pointer.new(:uint64, address).read_array_of_uint64(self[:num_items])
28
+ valuefun.nil? ? items : items.map{|i|valuefun.call(i)}
29
+ end
30
+ end
31
+
32
+ class TdbOptValue < FFI::Union
33
+ layout(
34
+ :ptr, :pointer,
35
+ :value, :uint64,
36
+ )
37
+ end
38
+
39
+ TDB_OPT_EVENT_FILTER = 101
40
+
41
+ attach_function :tdb_cons_init, [], :tdb_cons
42
+ attach_function :tdb_cons_open, [:tdb_cons, :string, :pointer, :uint64], :tdb_error
43
+ attach_function :tdb_cons_close, [:tdb_cons], :void
44
+ attach_function :tdb_cons_add, [:tdb_cons, :pointer, :uint64, :pointer, :pointer], :tdb_error
45
+ attach_function :tdb_cons_append, [:tdb_cons, :tdb], :tdb_error
46
+ attach_function :tdb_cons_finalize, [:tdb_cons], :tdb_error
47
+
48
+ attach_function :tdb_init, [], :tdb
49
+ attach_function :tdb_open, [:tdb, :string], :tdb_error
50
+ attach_function :tdb_close, [:tdb], :void
51
+
52
+ attach_function :tdb_lexicon_size, [:tdb, :tdb_field], :tdb_error
53
+
54
+ attach_function :tdb_get_field, [:tdb, :string], :tdb_error
55
+ attach_function :tdb_get_field_name, [:tdb, :tdb_field], :string
56
+
57
+ attach_function :tdb_get_item, [:tdb, :tdb_field, :pointer, :uint64], :tdb_item
58
+ attach_function :tdb_get_value, [:tdb, :tdb_field, :tdb_val, :pointer], :string
59
+ attach_function :tdb_get_item_value, [:tdb, :tdb_item, :pointer], :string
60
+
61
+ attach_function :tdb_get_uuid, [:tdb, :uint64], :pointer
62
+ attach_function :tdb_get_trail_id, [:tdb, :pointer, :pointer], :tdb_error
63
+
64
+ attach_function :tdb_error_str, [:tdb_error], :string
65
+
66
+ attach_function :tdb_num_trails, [:tdb], :uint64
67
+ attach_function :tdb_num_events, [:tdb], :uint64
68
+ attach_function :tdb_num_fields, [:tdb], :uint64
69
+ attach_function :tdb_min_timestamp, [:tdb], :uint64
70
+ attach_function :tdb_max_timestamp, [:tdb], :uint64
71
+
72
+ attach_function :tdb_version, [:tdb], :uint64
73
+
74
+ attach_function :tdb_cursor_new, [:tdb], :tdb_cursor
75
+ attach_function :tdb_cursor_free, [:tdb_cursor], :void
76
+ attach_function :tdb_cursor_next, [:tdb_cursor], TdbEvent.ptr
77
+ attach_function :tdb_get_trail, [:tdb_cursor, :uint64], :tdb_error
78
+ attach_function :tdb_get_trail_length, [:tdb_cursor], :uint64
79
+ attach_function :tdb_cursor_set_event_filter, [:tdb_cursor, :tdb_event_filter], :tdb_error
80
+
81
+ attach_function :tdb_event_filter_new, [], :tdb_event_filter
82
+ attach_function :tdb_event_filter_add_term, [:tdb_event_filter, :tdb_item, :int], :tdb_error
83
+ attach_function :tdb_event_filter_add_time_range, [:tdb_event_filter, :uint64, :uint64], :tdb_error
84
+ attach_function :tdb_event_filter_new_clause, [:tdb_event_filter], :tdb_error
85
+ attach_function :tdb_event_filter_new_match_none, [], :tdb_event_filter
86
+ attach_function :tdb_event_filter_new_match_all, [], :tdb_event_filter
87
+ attach_function :tdb_event_filter_free, [:tdb_event_filter], :void
88
+
89
+ attach_function :tdb_set_opt, [:tdb, :uint, TdbOptValue.by_value], :tdb_error
90
+ attach_function :tdb_set_trail_opt, [:tdb, :uint64, :uint, TdbOptValue.by_value], :tdb_error
91
+
92
+ def self.uuid_hex(uuid)
93
+ if uuid.is_a? FFI::Pointer
94
+ ary = uuid.read_bytes(16).unpack("NnnnnN")
95
+ uuid = "%08x-%04x-%04x-%04x-%04x%08x" % ary
96
+ end
97
+ uuid
98
+ end
99
+
100
+ def self.uuid_raw(uuid)
101
+ if uuid.is_a? String
102
+ ptr = FFI::MemoryPointer.new(:uint8, 16)
103
+ uuid = ptr.write_bytes(uuid.scan(/[0-9a-f]{2}/).map{|x|x.to_i(16)}.pack('C*'))
104
+ end
105
+ uuid
106
+ end
107
+
108
+ def self.tdb_item_is32(item); (item & 128) == 0 end
109
+ def self.tdb_item_field32(item); item & 127 end
110
+ def self.tdb_item_val32(item); (item >> 8) & 4294967295 end # UINT32_MAX
111
+
112
+ def self.tdb_item_field(item)
113
+ if tdb_item_is32(item)
114
+ tdb_item_field32(item)
115
+ else
116
+ (item & 127) | (((item >> 8) & 127) << 7)
117
+ end
118
+ end
119
+
120
+ def self.tdb_item_val(item)
121
+ if tdb_item_is32(item)
122
+ tdb_item_val32(item)
123
+ else
124
+ item >> 16
125
+ end
126
+ end
127
+
128
+ class TrailDBError < ::StandardError
129
+ def initialize(message, error = 0)
130
+ message += ": " + Traildb.tdb_error_str(error) if error != 0
131
+ super message
132
+ end
133
+ end
134
+
135
+ class TrailDBConstructor < FFI::AutoPointer
136
+ def initialize(path, ofields=[])
137
+ raise TrailDBError.new("Path is required") if path.nil?
138
+ super Traildb.tdb_cons_init()
139
+ n = ofields.size
140
+ ofield_names = FFI::MemoryPointer.new(:string, n)
141
+ ofield_names.write_array_of_pointer(ofields.map{|field|FFI::MemoryPointer.from_string(field)})
142
+ ret = Traildb.tdb_cons_open(self, path, ofield_names, n)
143
+ raise TrailDBError.new("Cannot open constructor", ret) if ret != 0
144
+ @path = path
145
+ @ofields = ofields
146
+ end
147
+
148
+ def add(uuid, tstamp, values)
149
+ tstamp = tstamp.to_i if tstamp.is_a? Time
150
+ uuid = Traildb.uuid_raw(uuid)
151
+ n = @ofields.size
152
+ value_array = FFI::MemoryPointer.new(:string, n)
153
+ value_array.write_array_of_pointer(values.map{|v|FFI::MemoryPointer.from_string(v)})
154
+ value_lengths = FFI::MemoryPointer.new(:uint64, n)
155
+ value_lengths.write_array_of_uint64(values.map{|v|v.size})
156
+ ret = Traildb.tdb_cons_add(self, uuid, tstamp, value_array, value_lengths)
157
+ raise TrailDBError.new("Too many values: %s" % values[ret]) if ret != 0
158
+ end
159
+
160
+ def append(db)
161
+ f = Traildb.tdb_cons_append(self, db)
162
+ if f < 0
163
+ raise TrailDBError.new("Wrong number of fields: %d" % db.num_fields, f)
164
+ elsif f > 0
165
+ raise TrailDBError.new("Too many values", f)
166
+ end
167
+ end
168
+
169
+ def finalize
170
+ ret = Traildb.tdb_cons_finalize(self)
171
+ raise TrailDBError.new("Could not finalize", ret) if ret != 0
172
+ TrailDB.new(@path)
173
+ end
174
+
175
+ def self.release(ptr)
176
+ Traildb.tdb_cons_close(ptr)
177
+ end
178
+ end
179
+
180
+ class TrailDBCursor < FFI::AutoPointer
181
+ include Enumerable
182
+
183
+ def initialize(cursor, cls, valuefun, parsetime, only_timestamp, event_filter_obj)
184
+ super cursor
185
+ @cls = cls
186
+ @valuefun = valuefun
187
+ @parsetime = parsetime
188
+ @only_timestamp = only_timestamp
189
+ if event_filter_obj
190
+ @event_filter_obj = event_filter_obj
191
+ ret = Traildb.tdb_cursor_set_event_filter(self, event_filter_obj)
192
+ raise TrailDBError.new("cursor_set_event_filter failed", ret) if ret != 0
193
+ end
194
+ end
195
+
196
+ def each
197
+ loop do
198
+ event = Traildb.tdb_cursor_next(self)
199
+ break if event.null?
200
+ timestamp = event[:timestamp]
201
+ timestamp = Time.at(timestamp) if @parsetime
202
+ if @only_timestamp
203
+ yield timestamp
204
+ else
205
+ items = event.tdb_items(@valuefun)
206
+ yield @cls.new(timestamp, *items)
207
+ end
208
+ end
209
+ end
210
+
211
+ def self.release(ptr)
212
+ Trailsdb.tdb_cursor_free(ptr)
213
+ end
214
+ end
215
+
216
+ class TrailDB < FFI::AutoPointer
217
+ attr_reader :num_trails, :num_events, :num_fields, :fields
218
+
219
+ def initialize(path)
220
+ super Traildb.tdb_init()
221
+ ret = Traildb.tdb_open(self, path)
222
+ raise TrailDBError.new("Could not open %s" % path, ret) if ret != 0
223
+ @num_trails = Traildb.tdb_num_trails(self)
224
+ @num_events = Traildb.tdb_num_events(self)
225
+ @num_fields = Traildb.tdb_num_fields(self)
226
+ @fields = @num_fields.times.map{|i|Traildb.tdb_get_field_name(self,i)}
227
+ @event_cls = Struct.new(*@fields.map(&:to_sym))
228
+ @uint64_ptr = FFI::MemoryPointer.new(:uint64)
229
+ end
230
+
231
+ def include?(uuidish)
232
+ self[uuidish]
233
+ true
234
+ rescue IndexError
235
+ false
236
+ end
237
+
238
+ def [](uuidish)
239
+ if uuidish.is_a? String
240
+ trail(get_trail_id(uuidish))
241
+ else
242
+ trail(uuidish)
243
+ end
244
+ end
245
+
246
+ def size
247
+ @num_trails
248
+ end
249
+
250
+ def trails(selected_uuids: nil, **kwds)
251
+ if selected_uuids.nil?
252
+ size.times.each.lazy.map do |i|
253
+ [get_uuid(i), trail(i, kwds)]
254
+ end
255
+ else
256
+ selected_uuids.each.lazy.map do |uuid|
257
+ begin
258
+ i = get_trail_id(uuid)
259
+ rescue IndexError
260
+ next
261
+ end
262
+ [uuid, trail(i, kwds)]
263
+ end
264
+ end
265
+ end
266
+
267
+ def trail(trail_id, parsetime: false, rawitems: false, only_timestamp: false, event_filter: nil)
268
+ cursor = Traildb.tdb_cursor_new(self)
269
+ ret = Traildb.tdb_get_trail(cursor, trail_id)
270
+ raise TrailDBError.new("Failed to create cursor", ret) if ret != 0
271
+ valuefun = rawitems ? nil : ->(item){get_item_value(item)}
272
+ event_filter_obj = case event_filter
273
+ when TrailDBEventFilter
274
+ event_filter
275
+ when Array
276
+ create_filter(event_filter)
277
+ else
278
+ nil
279
+ end
280
+ TrailDBCursor.new(cursor, @event_cls, valuefun, parsetime, only_timestamp, event_filter_obj)
281
+ end
282
+
283
+ def field(fieldish)
284
+ if fieldish.is_a? String
285
+ fieldish = @fields.index(fieldish)
286
+ end
287
+ fieldish
288
+ end
289
+
290
+ def lexicon(fieldish)
291
+ field = field(fieldish)
292
+ (1..lexicon_size(field)-1).lazy.map{|i|
293
+ get_value(field, i)
294
+ }
295
+ end
296
+
297
+ def lexicon_size(fieldish)
298
+ field = field(fieldish)
299
+ value = Traildb.tdb_lexicon_size(self, field)
300
+ raise TrailDBError.new("Invalid field index") if value == 0
301
+ value
302
+ end
303
+
304
+ def get_item(fieldish, value)
305
+ field = field(fieldish)
306
+ item = Traildb.tdb_get_item(self, field, value, value.size)
307
+ raise TrailDBError.new("No such value: '%s'" % value) if item.nil?
308
+ item
309
+ end
310
+
311
+ def get_item_value(item)
312
+ value = Traildb.tdb_get_item_value(self, item, @uint64_ptr)
313
+ raise TrailDBError.new("Error reading value") if value.nil?
314
+ value.slice(0, @uint64_ptr.read_uint64)
315
+ end
316
+
317
+ def get_value(fieldish, val)
318
+ field = field(fieldish)
319
+ value = Traildb.tdb_get_value(self, field, val, @uint64_ptr)
320
+ raise TrailDBError.new("Error reading value") if value.nil?
321
+ value.slice(0, @uint64_ptr.read_uint64)
322
+ end
323
+
324
+ def get_uuid(trail_id, raw=false)
325
+ uuid = Traildb.tdb_get_uuid(self, trail_id)
326
+ if uuid.nil?
327
+ raise ::IndexError
328
+ else
329
+ raw ? uuid.read_string : Traildb.uuid_hex(uuid)
330
+ end
331
+ end
332
+
333
+ def get_trail_id(uuid)
334
+ ret = Traildb.tdb_get_trail_id(self, Traildb.uuid_raw(uuid), @uint64_ptr)
335
+ raise ::IndexError if ret != 0
336
+ @uint64_ptr.read_uint64
337
+ end
338
+
339
+ def time_range(parsetime: false)
340
+ tmin = min_timestamp
341
+ tmax = max_timestamp
342
+ parsetime ? [Time.at(tmin), Time.at(tmax)] : [tmin, tmax]
343
+ end
344
+
345
+ def min_timestamp
346
+ Traildb.tdb_min_timestamp(self)
347
+ end
348
+
349
+ def max_timestamp
350
+ Traildb.tdb_max_timestamp(self)
351
+ end
352
+
353
+ def create_filter(event_filter)
354
+ TrailDBEventFilter.new(self, event_filter)
355
+ end
356
+
357
+ def apply_whitelist(uuids)
358
+ empty_filter = Traildb.tdb_event_filter_new_match_none()
359
+ all_filter = Traildb.tdb_event_filter_new_match_all()
360
+ value = TdbOptValue.new
361
+ value[:ptr] = empty_filter
362
+ Traildb.tdb_set_opt(self, TDB_OPT_EVENT_FILTER, value)
363
+ value[:ptr] = all_filter
364
+ uuids.each do |uuid|
365
+ begin
366
+ trail_id = get_trail_id(uuid)
367
+ Traildb.tdb_set_trail_opt(self, trail_id, TDB_OPT_EVENT_FILTER, value)
368
+ rescue IndexError
369
+ next
370
+ end
371
+ end
372
+ end
373
+
374
+ def apply_blacklist(uuids)
375
+ empty_filter = Traildb.tdb_event_filter_new_match_none()
376
+ all_filter = Traildb.tdb_event_filter_new_match_all()
377
+ value = TdbOptValue.new
378
+ value[:ptr] = all_filter
379
+ Traildb.tdb_set_opt(self, TDB_OPT_EVENT_FILTER, value)
380
+ value[:ptr] = empty_filter
381
+ uuids.each do |uuid|
382
+ begin
383
+ trail_id = get_trail_id(uuid)
384
+ Traildb.tdb_set_trail_opt(self, trail_id, TDB_OPT_EVENT_FILTER, value)
385
+ rescue IndexError
386
+ next
387
+ end
388
+ end
389
+ end
390
+
391
+ def self.release(ptr)
392
+ Traildb.tdb_close(ptr)
393
+ end
394
+ end
395
+
396
+ class TrailDBEventFilter < FFI::AutoPointer
397
+ def initialize(db, query)
398
+ super Traildb.tdb_event_filter_new()
399
+ if !query[0][0].is_a? Array
400
+ query = [query]
401
+ end
402
+ query.each_with_index do |clause, i|
403
+ if i > 0
404
+ ret = Traildb.tdb_event_filter_new_clause(self)
405
+ raise TrailDBError.new("Out of memory in create_filter", ret) if ret != 0
406
+ end
407
+ clause.each do |term|
408
+ ret = 0
409
+ if term.size == 2 and term[0].is_a? Integer and term[0].is_a? Integer
410
+ start_time, end_time = term
411
+ ret = Traildb.tdb_event_filter_add_time_range(self, start_time, end_time)
412
+ else
413
+ is_negative = false
414
+ if term.size == 3
415
+ field, value, is_negative = term
416
+ else
417
+ field, value = term
418
+ end
419
+ item = begin
420
+ db.get_item(field, value)
421
+ rescue TrailDBError, ValueError
422
+ 0
423
+ end
424
+ ret = Traildb.tdb_event_filter_add_term(self, item, is_negative ? 1 : 0)
425
+ end
426
+ raise TrailDBError.new("Out of memory in create_filter", ret) if ret != 0
427
+ end
428
+ end
429
+ end
430
+
431
+ def self.release(ptr)
432
+ Traildb.tdb_event_filter_free(ptr)
433
+ end
434
+ end
435
+ end
data/traildb.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "traildb/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "traildb"
8
+ spec.version = Traildb::VERSION
9
+ spec.authors = ["Ryosuke IWANAGA"]
10
+ spec.email = ["riywo.jp@gmail.com"]
11
+
12
+ spec.summary = %q{Ruby bindings for TrailDB}
13
+ spec.description = %q{Operate TrailDB from Ruby code using this gem.}
14
+ spec.homepage = "https://github.com/riywo/traildb-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "ffi"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.15"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "test-unit"
29
+ spec.add_development_dependency "pry"
30
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: traildb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryosuke IWANAGA
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Operate TrailDB from Ruby code using this gem.
84
+ email:
85
+ - riywo.jp@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - examples/tutorial_simple_traildb.rb
99
+ - examples/tutorial_wikipedia_sessions.rb
100
+ - lib/traildb.rb
101
+ - lib/traildb/version.rb
102
+ - traildb.gemspec
103
+ homepage: https://github.com/riywo/traildb-ruby
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.6.13
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Ruby bindings for TrailDB
127
+ test_files: []