groovy 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 36ab3d8425ae05fd7b069e75b1cb3f168a8a31605e2bd54d3b44285f715dbc92
4
+ data.tar.gz: 7d48ca3d630488d52c0fd60e73ac753d5b1658601f6803566838c563231cce9a
5
+ SHA512:
6
+ metadata.gz: 2dfafb96a0e3636a7e49c9319a40d7e7217d6c21ed48bc0be6e8a4a61aee9a7ce41f9d3499987a03d16e0dc15868988d6a03049a8aec401b70f96b4c405e47b4
7
+ data.tar.gz: 90e22b09f631228277f297c552f42bbdf0bfc9faaccbea13c769b2f68b91cc297c157a1557a101790d0497d2390ba466f4f44f97bf5ac1a3d4f267666b36465e
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *~
2
+ *.gem
3
+ test
4
+ log
5
+ pkg
6
+ example/db
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ # specified in groovy.gemspec
4
+ gemspec
data/example/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gem 'rack'
3
+ gem 'groovy', path: '..'
@@ -0,0 +1,43 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ groovy (0.1.0)
5
+ rroonga (~> 7.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ archive-zip (0.12.0)
11
+ io-like (~> 0.3.0)
12
+ gqtp (1.0.6)
13
+ groonga-client (0.6.0)
14
+ gqtp (>= 1.0.4)
15
+ groonga-command (>= 1.2.8)
16
+ groonga-command-parser (>= 1.1.0)
17
+ hashie
18
+ groonga-command (1.4.1)
19
+ json
20
+ groonga-command-parser (1.1.4)
21
+ groonga-command (>= 1.4.0)
22
+ json-stream
23
+ hashie (3.6.0)
24
+ io-like (0.3.0)
25
+ json (2.2.0)
26
+ json-stream (0.2.1)
27
+ pkg-config (1.3.7)
28
+ rack (2.0.6)
29
+ rroonga (7.1.1)
30
+ archive-zip
31
+ groonga-client (>= 0.0.3)
32
+ json
33
+ pkg-config
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ groovy!
40
+ rack
41
+
42
+ BUNDLED WITH
43
+ 1.16.1
data/example/config.ru ADDED
@@ -0,0 +1,27 @@
1
+ require 'bundler/setup'
2
+ require 'groovy'
3
+ Groovy.init('./db/test')
4
+
5
+ class Place
6
+ include Groovy::Model
7
+
8
+ # table_options type: :hash
9
+ column :name, String
10
+ column :description, String, searchable: true
11
+ timestamps!
12
+ end
13
+
14
+ Place.delete_all
15
+
16
+ 10.times do |i|
17
+ Place.create!(name: "Place #{i}", description: "A nice place")
18
+ end
19
+
20
+ Place.last.delete
21
+
22
+ app = Proc.new do |env|
23
+ body = Place.all.collect(&:as_json)
24
+ [200, { 'Content-Type' => 'text/plain' }, [body]]
25
+ end
26
+
27
+ run app
data/groovy.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/groovy", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "groovy"
6
+ s.version = Groovy::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['Tomás Pollak']
9
+ s.email = ['tomas@forkhq.com']
10
+ s.homepage = "https://github.com/tomas/groovy"
11
+ s.summary = "A wrapper around Groonga/Rroonga"
12
+ s.description = "Allows using Groonga in your models a-la ActiveRecord."
13
+
14
+ # s.required_rubygems_version = ">= 1.3.6"
15
+ # s.rubyforge_project = "groovy"
16
+
17
+ s.add_development_dependency "bundler", ">= 1.0.0"
18
+ s.add_runtime_dependency "rroonga", "~> 7.1"
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
22
+ s.require_path = 'lib'
23
+ end
data/lib/groovy.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'groonga'
2
+ require File.expand_path(File.dirname(__FILE__)) + '/groovy/model'
3
+
4
+ module Groovy
5
+ VERSION = '0.1.0'.freeze
6
+
7
+ def self.init(db_path, opts = {})
8
+ if File.exist?(db_path)
9
+ puts "Opening DB"
10
+ Groonga::Database.open(db_path)
11
+ else
12
+ dir = File.dirname(db_path)
13
+ puts "Creating DB in #{dir}"
14
+ FileUtils.mkdir_p(dir)
15
+ Groonga::Database.create(path: db_path)
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,275 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/query'
2
+ require File.expand_path(File.dirname(__FILE__)) + '/types'
3
+ require File.expand_path(File.dirname(__FILE__)) + '/schema'
4
+
5
+ class Hash
6
+ def symbolize_keys
7
+ self.inject({}) { |memo, (k,v)| memo[k.to_sym] = v; memo }
8
+ end
9
+ end unless {}.respond_to?(:symbolize_keys)
10
+
11
+ module Groovy
12
+ module Model
13
+
14
+ SEARCH_TABLE_NAME = 'Terms'
15
+
16
+ def self.included(base)
17
+ base.extend(ClassMethods)
18
+ base.include(Forwardable)
19
+ base.table_name = base.name + 's'
20
+
21
+ if base.table.nil?
22
+ # abort "Please set up your database before declaring your models."
23
+ else
24
+ base.extend(PatriciaTrieMethods) if base.table.is_a?(Groonga::PatriciaTrie)
25
+ base.class_eval do
26
+ attribute_names.each do |col|
27
+ add_accessor(col)
28
+ end
29
+ end # if base.table
30
+ end
31
+ end
32
+
33
+ module ClassMethods
34
+ extend Forwardable
35
+ attr_accessor :table_name
36
+
37
+ def validatable!
38
+ include(ActiveModel::Validations)
39
+ end
40
+
41
+ def table
42
+ # raise "Table name not set!" if table_name.nil?
43
+ # schema.table
44
+ Groonga[table_name]
45
+ end
46
+
47
+ def table_options(opts)
48
+ @table_options = opts
49
+ end
50
+
51
+ def schema
52
+ @schema ||= Schema.new(table_name, @table_options)
53
+ end
54
+
55
+ def column(name, type, options = {})
56
+ column_type = Types.map(type)
57
+ schema.column(name, column_type, options)
58
+ add_accessor(name)
59
+ end
60
+
61
+ def timestamps!(opts = {})
62
+ column(:created_at, 'Time')
63
+ column(:updated_at, 'Time')
64
+ end
65
+
66
+ # def columns
67
+ # table.columns # .collect { |x| x.name.split('.').last.to_sym }
68
+ # end
69
+
70
+ def add_accessor(col)
71
+ define_method(col) { self[col] }
72
+ define_method("#{col}=") { |val| self[col] = val }
73
+ end
74
+
75
+ def attribute_names
76
+ table.columns.select { |col| !col.reference_column? }.map { |x| x.name.split('.').last.to_sym }
77
+ end
78
+
79
+ def scope(name, obj)
80
+ define_singleton_method(name) do |*args|
81
+ obj.respond_to?(:call) ? obj.call(*args) : obj
82
+ end
83
+ end
84
+
85
+ def find(id)
86
+ if record = table[id] and record.id
87
+ new(record.attributes, record)
88
+ end
89
+ end
90
+
91
+ def insert(key, attributes = nil)
92
+ if table.support_key?
93
+ table.add(key, attributes)
94
+ else # key is attributes
95
+ set_timestamp(key, :created_at)
96
+ set_timestamp(key, :updated_at)
97
+ table.add(key)
98
+ end
99
+ end
100
+
101
+ def create(key, attributes = nil)
102
+ if record = insert(key, attributes)
103
+ new(record.attributes, record)
104
+ end
105
+ end
106
+
107
+ def create!(key, attributes = nil)
108
+ create(key, attributes) or raise "Invalid!"
109
+ end
110
+
111
+ def delete_all
112
+ schema.rebuild!
113
+ end
114
+
115
+ def search_columns
116
+ @search_columns ||= []
117
+ end
118
+
119
+ def searchable_on(*fields)
120
+ fields.each { |f| add_index_on(f) }
121
+ end
122
+
123
+ def add_index_on(field)
124
+ ensure_search_table
125
+ search_columns.push(field)
126
+ Groonga::Schema.change_table(SEARCH_TABLE_NAME) do |table|
127
+ table.index([table_name, field].join('.'))
128
+ end
129
+ end
130
+
131
+ def ensure_search_table
132
+ return if Groonga[SEARCH_TABLE_NAME]
133
+ Groonga::Schema.create_table(SEARCH_TABLE_NAME, {
134
+ type: :patricia_trie,
135
+ normalizer: :NormalizerAuto,
136
+ default_tokenizer: "TokenBigram"
137
+ })
138
+ end
139
+
140
+ # def column(name)
141
+ # Groonga["#{table_name}.#{name}"] # .search, .similar_search, etc
142
+ # end
143
+
144
+ def similar_search(col, q)
145
+ table.select { |r| r[col].similar_search(q) }
146
+ # table.select("#{col}:#{q}", operator: Groonga::Operation::SIMILAR)
147
+ end
148
+
149
+ def all
150
+ Query.new(self, table)
151
+ end
152
+
153
+ def_instance_delegators :all, :first, :last
154
+
155
+ def find_by(params)
156
+ where(params).first
157
+ end
158
+
159
+ [:search, :where, :not, :sort_by, :limit, :offset].each do |scope_method|
160
+ define_method scope_method do |*args|
161
+ Query.new(self, table).tap do |q|
162
+ q.public_send(scope_method, *args)
163
+ end
164
+ end
165
+ end
166
+
167
+ # this seems to be the same as: `table[id]`
168
+ # def search(key, options = nil)
169
+ # raise "Not supported!" unless table.respond_to?(:search)
170
+ # table.search(key, options)
171
+ # end
172
+
173
+ def_instance_delegators :table, :count, :size
174
+
175
+ def set_timestamp(obj, key_name)
176
+ obj[key_name] = Time.now if attribute_names.include?(key_name.to_sym)
177
+ end
178
+
179
+ end
180
+
181
+ module PatriciaTrieMethods
182
+ extend Forwardable
183
+
184
+ # def_instance_delegators :@table, :scan, :search, :prefix_search, :open_prefix_cursor, :tag_keys
185
+ def_instance_delegators :table, :scan, :search, :prefix_search, :open_prefix_cursor, :tag_keys
186
+
187
+ def each_with_prefix(prefix, options = {}, &block)
188
+ table.open_prefix_cursor(prefix, options) do |cursor|
189
+ cursor.each { |r| yield r }
190
+ end
191
+ end
192
+ end
193
+
194
+ attr_reader :attributes, :record, :changes
195
+
196
+ def initialize(attributes, record = nil)
197
+ @attributes = attributes.symbolize_keys.slice(*self.class.attribute_names)
198
+ @record = record
199
+ @changes = {}
200
+ end
201
+
202
+ def key
203
+ record.respond_to?(:_key) ? record._key : record.id
204
+ end
205
+
206
+ def [](key)
207
+ attributes[key.to_sym]
208
+ end
209
+
210
+ def []=(key, val)
211
+ raise "Invalid attribute: #{key}" unless attributes.has_key?(key.to_sym)
212
+ changes[key.to_sym] = [self[key], val]
213
+ attributes[key.to_sym] = val
214
+ end
215
+
216
+ def increment(values, do_save = true)
217
+ values.each { |key, num| self[key] += num }
218
+ save if do_save
219
+ end
220
+
221
+ def dirty?
222
+ changes.any?
223
+ end
224
+
225
+ def update_attributes(obj)
226
+ obj.each { |k,v| self[k] = v }
227
+ update
228
+ end
229
+
230
+ def save(options = {})
231
+ return false if respond_to?(:invalid) and invalid?
232
+ @record ? update : create
233
+ end
234
+
235
+ def save!(options = {})
236
+ raise "Invalid!" unless save
237
+ end
238
+
239
+ def delete
240
+ record.delete
241
+ self
242
+ end
243
+
244
+ def reload
245
+ raise "Not persisted" if key.nil?
246
+ record = self.class.table[key]
247
+ @attributes = record.attributes.symbolize_keys
248
+ @changes = {}
249
+ self
250
+ end
251
+
252
+ def as_json(options = {})
253
+ attributes
254
+ end
255
+
256
+ private
257
+
258
+ def create
259
+ @record = self.class.insert(attributes)
260
+ self
261
+ end
262
+
263
+ def update
264
+ raise "Not persisted" unless key
265
+ changes.merge.each do |key, values|
266
+ # puts "Updating #{key} from #{values[0]} to #{values[1]}"
267
+ record[key] = values.last
268
+ end
269
+ self.class.set_timestamp(record, :updated_at)
270
+ @changes = {}
271
+ self
272
+ end
273
+
274
+ end
275
+ end
@@ -0,0 +1,182 @@
1
+ module Groovy
2
+
3
+ class Query
4
+ include Enumerable
5
+ AND = '+'.freeze
6
+ NOT = '-'.freeze
7
+
8
+ attr_reader :parameters, :sorting
9
+
10
+ # options:
11
+ # - "operator"
12
+ # - "result"
13
+ # - "name"
14
+ # - "syntax"
15
+ # - "allow_pragma"
16
+ # - "allow_column"
17
+ # - "allow_update"
18
+ # - "allow_leading_not"
19
+ # - "default_column"
20
+
21
+ def initialize(model, table, options = {})
22
+ @model, @table, @options = model, table, options
23
+ @parameters = options.delete(:parameters) || []
24
+ @sorting = { limit: -1, offset: 0 }
25
+ @default_sort_key = table.is_a?(Groonga::Hash) ? '_key' : '_id'
26
+ end
27
+
28
+ def merge_with!(another)
29
+ # parameters.merge!(another.parameters)
30
+ parameters.concat(another.parameters)
31
+ sorting.merge!(another.sorting)
32
+ self
33
+ end
34
+
35
+ def search(obj)
36
+ obj.each do |col, q|
37
+ raise "Not a full-text search column: #{col}" unless model.search_columns.include?(col)
38
+ parameters.push(AND + "(#{col}:@#{q})")
39
+ end
40
+ end
41
+
42
+ # http://groonga.org/docs/reference/grn_expr/query_syntax.html
43
+ # TODO: support match_columns (search value in two or more columns)
44
+ def where(conditions = nil)
45
+ case conditions
46
+ when String # "foo:bar"
47
+ parameters.push(AND + "(#{map_operator(conditions)})")
48
+ when Hash # { foo: 'bar' } or { views: 1..100 }
49
+ conditions.each do |key, val|
50
+ if val.is_a?(Range)
51
+ parameters.push(AND + [key, val.min].join(':>=')) if val.min # lte
52
+ parameters.push(AND + [key, val.max].join(':<=')) if val.max # gte
53
+ elsif val.is_a?(Regexp)
54
+ str = val.source.gsub(/[^a-z]/, '')
55
+ param = val.source[0] == '^' ? ':^' : ':~' # starts with or regexp
56
+ parameters.push(AND + [key, str].join(param))
57
+ else
58
+ parameters.push(AND + [key, val.to_s].join(':'))
59
+ end
60
+ end
61
+ # when Array # ["foo:?", val]
62
+ # parameters.push(conditions.first.sub('?', conditions.last))
63
+ when NilClass
64
+ # doing where.not probably
65
+ else
66
+ raise 'not supported'
67
+ end
68
+ self
69
+ end
70
+
71
+ def not(conditions = {})
72
+ case conditions
73
+ when String # "foo:bar"
74
+ parameters.push(NOT + "(#{map_operator(conditions)})")
75
+ when Hash # { foo: 'bar' }
76
+ conditions.each do |key, val|
77
+ if val.is_a?(Range)
78
+ parameters.push(AND + [key, val.min].join(':<=')) if val.min # gte
79
+ parameters.push(AND + [key, val.max].join(':>=')) if val.max # lte
80
+ else
81
+ parameters.push(AND + [key, val.to_s].join(':!')) # not
82
+ end
83
+ end
84
+ # when Array # ["foo:?", val]
85
+ # parameters.push(conditions.first.sub('?', conditions.last))
86
+ else
87
+ raise 'not supported'
88
+ end
89
+ self
90
+ end
91
+
92
+ def limit(num)
93
+ @limit = num
94
+ self
95
+ end
96
+
97
+ def offset(num)
98
+ @offset = num
99
+ self
100
+ end
101
+
102
+ # sort_by(title: :asc)
103
+ def sort_by(hash)
104
+ sorting[:by] = hash.keys.map do |key|
105
+ { key: key.to_s, order: hash[key] }
106
+ end
107
+ self
108
+ end
109
+
110
+ def all
111
+ @all ||= results.map { |r| model.new(r.attributes['_value']['_key'], r) }
112
+ end
113
+
114
+ def size
115
+ results.size
116
+ end
117
+
118
+ alias_method :count, :size
119
+
120
+ def to_a
121
+ all
122
+ end
123
+
124
+ def [](index)
125
+ all[index]
126
+ end
127
+
128
+ def each(&block)
129
+ all.each { |r| block.call(r) }
130
+ end
131
+
132
+ def last
133
+ all[size-1]
134
+ end
135
+
136
+ private
137
+ attr_reader :model, :table, :options
138
+
139
+ def results
140
+ @results ||= execute
141
+ end
142
+
143
+ def execute
144
+ set = if parameters.any?
145
+ query = parameters.join(" ").gsub(/\s(\w)/, '\ \1')
146
+ puts query if ENV['DEBUG']
147
+ table.select(query, options)
148
+ else
149
+ table.select(options)
150
+ end
151
+
152
+ set.sort(sort_key_and_order, {
153
+ limit: sorting[:limit],
154
+ offset: sorting[:offset]
155
+ })
156
+ end
157
+
158
+ def map_operator(str)
159
+ str.sub(' = ', ':')
160
+ .sub(' != ', ':!')
161
+ .sub(' ~ ', ':~')
162
+ .sub(' < ', ':<')
163
+ .sub(' > ', ':>')
164
+ .sub(' <= ', ':<=')
165
+ .sub(' >= ', ':>=')
166
+ end
167
+
168
+ def sort_key_and_order
169
+ sorting[:by] or [{ key: @default_sort_key, order: :asc }]
170
+ end
171
+
172
+ def method_missing(name, *args)
173
+ if model.respond_to?(name)
174
+ other = model.public_send(name, *args)
175
+ merge_with!(other)
176
+ else
177
+ super
178
+ end
179
+ end
180
+ end
181
+
182
+ end
@@ -0,0 +1,122 @@
1
+ module Groovy
2
+ class Schema
3
+ attr_reader :table, :table_name
4
+
5
+ def initialize(table_name, opts = {})
6
+ @table_name, @opts = table_name, opts
7
+ @columns = {}
8
+ end
9
+
10
+ def table
11
+ @table ||= Groonga[table_name]
12
+ end
13
+
14
+ def rebuild!
15
+ remove_table! if table
16
+ create_table!
17
+ @columns.each do |name, spec|
18
+ check_and_add_column(name, spec[:type], spec[:options])
19
+ end
20
+ puts "done rebuilding"
21
+ end
22
+
23
+ def ensure_created!
24
+ create_table! if table.nil?
25
+ end
26
+
27
+ def column(name, type, options = {})
28
+ ensure_created!
29
+ @columns[name] = { type: type, options: options }
30
+ check_and_add_column(name, type, options)
31
+ end
32
+
33
+ def check_and_add_column(name, type, options)
34
+ add_column(name, type, options) unless has_column?(name, type)
35
+ end
36
+
37
+ def has_column?(name, type)
38
+ table.columns.any? do |col|
39
+ col.name == "#{table_name}.#{name}"
40
+ end
41
+ end
42
+
43
+ def add_column(name, type, options = {})
44
+ # puts "Adding column #{name}"
45
+ Groonga::Schema.change_table(table_name) do |table|
46
+ table.public_send(type, name, options)
47
+ end
48
+ end
49
+
50
+ def create_table!
51
+ # puts "creating table!"
52
+ Groonga::Schema.create_table(table_name, @opts)
53
+ end
54
+
55
+ def remove_table!
56
+ # puts "removing table!"
57
+ Groonga::Schema.remove_table(table_name)
58
+ @table = nil
59
+ end
60
+ end
61
+ end
62
+
63
+ def load_schema!
64
+ Groonga::Schema.create_table("Sources")
65
+ Groonga::Schema.create_table("Topics")
66
+ Groonga::Schema.create_table("Tags", type: :patricia_trie)
67
+ Groonga::Schema.create_table("Links", type: :hash)
68
+ Groonga::Schema.create_table("Tweeters", type: :hash)
69
+ Groonga::Schema.create_table("Mentions")
70
+ Groonga::Schema.create_table("Subscribers")
71
+
72
+ Groonga::Schema.change_table("Sources") do |table|
73
+ table.short_text("name")
74
+ table.short_text("twitter_user_name")
75
+ end
76
+
77
+ Groonga::Schema.change_table("Topics") do |table|
78
+ table.reference("most_mentioned", "Links")
79
+ table.uint32("mentions_count")
80
+ table.uint32("links_count")
81
+ end
82
+
83
+ Groonga::Schema.change_table("Links") do |table|
84
+ table.reference("source", "Sources")
85
+ table.reference("topic", "Topics")
86
+ table.reference("tags", "Tags", type: :vector)
87
+ # table.short_text("url")
88
+ table.short_text("title")
89
+ table.short_text("image")
90
+ table.short_text("description") # less than 4K bytes
91
+ table.uint32("mentions_count")
92
+ table.uint32("hits_count")
93
+ table.boolean("posted")
94
+ table.boolean("removed")
95
+ table.short_text("snapshot")
96
+ table.uint32("posted_tweet_id")
97
+ end
98
+
99
+ Groonga::Schema.change_table("Tweeters") do |table|
100
+ table.short_text("name")
101
+ table.short_text("twitter_name")
102
+ table.uint32("mentions_count")
103
+ end
104
+
105
+ Groonga::Schema.change_table("Mentions") do |table|
106
+ table.reference("source", "Sources")
107
+ table.reference("link", "Links")
108
+ table.reference("tweeter", "Tweeters")
109
+ table.uint32("tweet_id")
110
+ table.short_text("content")
111
+ table.time("created_at")
112
+ end
113
+
114
+ Groonga::Schema.change_table("Subscribers") do |table|
115
+ table.short_text("name")
116
+ table.short_text("email")
117
+ table.short_text("timezone")
118
+ table.short_text("token")
119
+ table.uint32("received_count")
120
+ table.time("last_received_at")
121
+ end
122
+ end
@@ -0,0 +1,44 @@
1
+ module Groovy
2
+
3
+ module Types
4
+
5
+ # BIGRAM
6
+ # BOOL
7
+ # BOOLEAN
8
+ # DELIMIT
9
+ # FLOAT
10
+ # INT16
11
+ # INT32
12
+ # INT64
13
+ # INT8
14
+ # LONG_TEXT
15
+ # MECAB
16
+ # OBJECT
17
+ # SHORT_TEXT
18
+ # TEXT
19
+ # TIME
20
+ # TRIGRAM
21
+ # UINT16
22
+ # UINT32
23
+ # UINT64
24
+ # UINT8
25
+ # UNIGRAM
26
+
27
+ MAPPINGS = {
28
+ 'String' => 'short_text',
29
+ 'Text' => 'text',
30
+ 'Float' => 'float',
31
+ 'Bool' => 'boolean',
32
+ 'Boolean' => 'boolean',
33
+ 'Integer' => 'int32',
34
+ 'BigDecimal' => 'int64',
35
+ 'Time' => 'time'
36
+ }
37
+
38
+ def self.map(type)
39
+ MAPPINGS[type.to_s] or raise "Invalid type: #{type}"
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,3 @@
1
+ require './lib/groovy'
2
+ require 'rspec/mocks'
3
+
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: groovy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tomás Pollak
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rroonga
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '7.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '7.1'
41
+ description: Allows using Groonga in your models a-la ActiveRecord.
42
+ email:
43
+ - tomas@forkhq.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - example/Gemfile
51
+ - example/Gemfile.lock
52
+ - example/config.ru
53
+ - groovy.gemspec
54
+ - lib/groovy.rb
55
+ - lib/groovy/model.rb
56
+ - lib/groovy/query.rb
57
+ - lib/groovy/schema.rb
58
+ - lib/groovy/types.rb
59
+ - spec/groovy_spec.rb
60
+ homepage: https://github.com/tomas/groovy
61
+ licenses: []
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.7.3
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: A wrapper around Groonga/Rroonga
83
+ test_files: []