gros_calin 0.0.1
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 +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +124 -0
- data/Rakefile +10 -0
- data/bin/gros_calin +6 -0
- data/config.ru +5 -0
- data/gros_calin.gemspec +40 -0
- data/lib/gros_calin/cli.rb +42 -0
- data/lib/gros_calin/config.rb +103 -0
- data/lib/gros_calin/driver.rb +39 -0
- data/lib/gros_calin/mongo_db.rb +48 -0
- data/lib/gros_calin/mysql.rb +20 -0
- data/lib/gros_calin/version.rb +3 -0
- data/lib/gros_calin.rb +61 -0
- data/romain-gary.jpg +0 -0
- data/spec/gros_calin/config_spec.rb +134 -0
- data/spec/gros_calin/driver_spec.rb +23 -0
- data/spec/gros_calin/mongodb_spec.rb +49 -0
- data/spec/gros_calin/mysql_spec.rb +17 -0
- data/spec/gros_calin_spec.rb +82 -0
- data/spec/spec_helper.rb +21 -0
- metadata +383 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b84400b70034e273680e1f01aaaa4db3ff19ffc9
|
4
|
+
data.tar.gz: 8fe9102cc4394b78aa0dd3f61c97db7600effc83
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ba4e596de0a7d661e85866d2bf81bef0af8da0d9f2eee1e7404b15213477254ab0c83c28c9ec1c467e5de0945b8ce08d35cc39bf14ac3a047a5cd4742d0df29a
|
7
|
+
data.tar.gz: 228a27a22e4113257426183c6aa8182a04255dd2ec887b5477f2b508d28f97bc7bcf925c1f3c0f98c1f2f46a27d9eac76612ca937446aa9bc15c2f1d123b35d0
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
- 2.1.1
|
6
|
+
- 2.1.5
|
7
|
+
notifications:
|
8
|
+
hipchat:
|
9
|
+
rooms:
|
10
|
+
secure: NvtShOCmF+gKzPfUG5Gsd+Ibf5EnVtl1IQD033iRG1rOzSMejp64CYiRMQ3xjEpSKMZJ9w08Lem0WQyafEe5FbiHvDWb0nbHh60wj5QILeRb6Ajf5htSGWulZtR2yr9NIhxqfEZveXXLiH4xuqLxQ5rvM0jpt7enUTKKQFcRjSk=
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 ServeBox
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# Gros-Câlin
|
2
|
+
|
3
|
+
Share your database queries via HTTP/JSON.
|
4
|
+
|
5
|
+
[](https://travis-ci.org/servebox/gros_calin)
|
6
|
+
[](https://gemnasium.com/servebox/gros_calin)
|
7
|
+
[](https://coveralls.io/r/servebox/gros_calin)
|
8
|
+
[](https://codeclimate.com/github/servebox/gros_calin)
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Install the gem:
|
13
|
+
|
14
|
+
$ gem install gros_calin
|
15
|
+
|
16
|
+
Depending on the drivers you'd like to use to connect your databases, you'll
|
17
|
+
also have to install one or more of the following gems (see the
|
18
|
+
_Available drivers_ section below):
|
19
|
+
|
20
|
+
* mysql2 (MySQL)
|
21
|
+
* moped (MongoDB)
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Create a configuration file (see the _Configuration_ section below), then start
|
26
|
+
the server:
|
27
|
+
|
28
|
+
$ gros_calin
|
29
|
+
|
30
|
+
If you want to place the process in the background:
|
31
|
+
|
32
|
+
$ gros_calin -d
|
33
|
+
|
34
|
+
By default, the server searches for a `config.yml` file in the current
|
35
|
+
directory. To point to a specific location, use the `-c` flag:
|
36
|
+
|
37
|
+
$ gros_calin -c /path/to/config.yml
|
38
|
+
|
39
|
+
The server binds to the port `3313`, use the `-p` flag to change the port
|
40
|
+
number:
|
41
|
+
|
42
|
+
$ gros_calin -p 8080
|
43
|
+
|
44
|
+
To stop the server, hit `Ctrl^C` or, if you placed it in the background:
|
45
|
+
|
46
|
+
$ gros_calin stop
|
47
|
+
|
48
|
+
## Configuration
|
49
|
+
|
50
|
+
Configuration takes place in a [YAML](http://en.wikipedia.org/wiki/YAML) file.
|
51
|
+
First declare your datasources using one of the available drivers, then list the
|
52
|
+
queries you'd like to give a hug.
|
53
|
+
|
54
|
+
### HTTP endpoints
|
55
|
+
|
56
|
+
* List available datasources: `http://localhost:3313/`
|
57
|
+
* List available hugs for a datasource: `http://localhost:3313/<datasource>`
|
58
|
+
* Query a specific hug: `http://localhost:3313/<datasource>/<hug>`
|
59
|
+
|
60
|
+
### Available drivers
|
61
|
+
|
62
|
+
#### MySQL
|
63
|
+
|
64
|
+
```yaml
|
65
|
+
myapp_datasource:
|
66
|
+
driver: "mysql"
|
67
|
+
options:
|
68
|
+
host: "db.example.com"
|
69
|
+
username: "operator"
|
70
|
+
password: "secret"
|
71
|
+
database: "myapp"
|
72
|
+
hugs:
|
73
|
+
sign_ups: "SELECT count(id) AS sign_ups, country_code FROM users WHERE created_at DATE_SUB( NOW(), INTERVAL 24 HOUR) GROUP by country_code;"
|
74
|
+
# another_datasource:
|
75
|
+
```
|
76
|
+
|
77
|
+
See the [mysql2](https://github.com/brianmario/mysql2) client for a list
|
78
|
+
of [available connection
|
79
|
+
options](https://github.com/brianmario/mysql2#connection-options).
|
80
|
+
|
81
|
+
#### MongoDB
|
82
|
+
|
83
|
+
```yaml
|
84
|
+
projects_datasource:
|
85
|
+
driver: "mongodb"
|
86
|
+
options:
|
87
|
+
hosts:
|
88
|
+
- replset1.example.com:27017
|
89
|
+
- replset2.example.com:27017
|
90
|
+
- replset3.example.com:27017
|
91
|
+
username: "operator"
|
92
|
+
password: "secret"
|
93
|
+
hugs:
|
94
|
+
issues: "db.projects.find( { score: { $lt: 3.8 } } ).sort(score: -1).toArray()"
|
95
|
+
status: "{ failures: db.projects.find( { status: 'failed' } ).count(), success: db.projects.find( { status: 'success' } ).count() }"
|
96
|
+
average_score: "db.builds.aggregate( { $group: { _id: '$project_id', builds: { $avg: '$score' } } }).result"
|
97
|
+
# another_datasource:
|
98
|
+
```
|
99
|
+
|
100
|
+
## Frequently asked questions
|
101
|
+
|
102
|
+
### Is it fast?
|
103
|
+
|
104
|
+
Well, it depends.
|
105
|
+
|
106
|
+
### Does it scale?
|
107
|
+
|
108
|
+
It can serves up to a billion RPM (you'll have to rewrite it in Erlang, though).
|
109
|
+
|
110
|
+
### "Gros-Câlin"?
|
111
|
+
|
112
|
+
Gros-Câlin (_Big Cuddle_) is named after the eponymous novel written by Romain
|
113
|
+
Gary under the pen name Émile Ajar. In the book, M. Cousin, a statistician,
|
114
|
+
lives with a python which hugs him tight and helps him cope with loneliness.
|
115
|
+
|
116
|
+

|
117
|
+
|
118
|
+
## Contributing
|
119
|
+
|
120
|
+
1. Fork it
|
121
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
122
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
123
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
124
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/gros_calin
ADDED
data/config.ru
ADDED
data/gros_calin.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gros_calin/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gros_calin"
|
8
|
+
spec.version = GrosCalin::VERSION
|
9
|
+
spec.authors = ["Jef Mathiot"]
|
10
|
+
spec.email = ["jeff.mathiot@gmail.com"]
|
11
|
+
spec.summary = %q{Make database queries available via HTTP}
|
12
|
+
spec.description = %q{Make database queries available via HTTP}
|
13
|
+
spec.homepage = "https://github.com/servebox/gros_calin"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
22
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
23
|
+
spec.add_development_dependency 'mocha', '~> 1.1', '>= 1.1.0'
|
24
|
+
spec.add_development_dependency 'coveralls', '~> 0.7', '>= 0.7.1'
|
25
|
+
spec.add_development_dependency 'minitest', '~> 5.4', '>= 5.4.1'
|
26
|
+
spec.add_development_dependency 'minitest-implicit-subject', '~> 1.4', '>= 1.4.0'
|
27
|
+
spec.add_development_dependency 'rb-readline', '~> 0.5', '>= 0.5.0'
|
28
|
+
spec.add_development_dependency 'guard', '~> 2.11', '>= 2.11.1'
|
29
|
+
spec.add_development_dependency 'guard-minitest', '~> 2.3', '>= 2.3.2'
|
30
|
+
|
31
|
+
spec.add_development_dependency 'mysql2', '~> 0.3', '>= 0.3.18'
|
32
|
+
spec.add_development_dependency 'moped', '~> 2.0', '>= 2.0.3'
|
33
|
+
|
34
|
+
spec.add_dependency 'sinatra', '~> 1.4', '>= 1.4.5'
|
35
|
+
spec.add_dependency 'sinatra-contrib', '~> 1.4', '>= 1.4.2'
|
36
|
+
spec.add_dependency 'rack', '~> 1.6', '>= 1.6.0'
|
37
|
+
spec.add_dependency 'thin', '~> 1.6', '>= 1.6.3'
|
38
|
+
spec.add_dependency 'thor', '~> 0.19', '>= 0.19.1'
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module GrosCalin
|
4
|
+
|
5
|
+
class CLI < Thor
|
6
|
+
|
7
|
+
desc "start", "Starts the server"
|
8
|
+
option :port, aliases: %w(p), type: :numeric, default: '3313',
|
9
|
+
desc: "The port number to assign"
|
10
|
+
option :daemon, aliases: %w(d), type: :boolean, default: false,
|
11
|
+
desc: "Place the server process in the background"
|
12
|
+
option :config, aliases: %w(-c), type: :string,
|
13
|
+
desc: 'Override path to configuration file', default: './config.yml'
|
14
|
+
|
15
|
+
def start
|
16
|
+
command = "thin -R #{config_ru} start -p #{options[:port]}"
|
17
|
+
if options[:config]
|
18
|
+
command.prepend "export GROS_CALIN_CONFIG=#{options[:config]}; "
|
19
|
+
end
|
20
|
+
command << ' -d' if options[:daemon]
|
21
|
+
system command
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "stop", "Stops the server"
|
25
|
+
|
26
|
+
def stop
|
27
|
+
system "thin stop"
|
28
|
+
end
|
29
|
+
|
30
|
+
default_task :start
|
31
|
+
|
32
|
+
no_tasks do
|
33
|
+
|
34
|
+
def config_ru
|
35
|
+
File.expand_path(File.join(File.dirname(__FILE__), '../../config.ru'))
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module GrosCalin
|
4
|
+
|
5
|
+
class Collection < Array
|
6
|
+
|
7
|
+
def json
|
8
|
+
map(&:json)
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(id)
|
12
|
+
find{ |item| item.respond_to?(:id) && item.id == id }
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
module Identifier
|
18
|
+
|
19
|
+
def self.included(base)
|
20
|
+
base.send :attr_reader, :id
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class Datasource
|
26
|
+
include Identifier
|
27
|
+
|
28
|
+
attr_reader :driver
|
29
|
+
|
30
|
+
def initialize(id, driver, options={})
|
31
|
+
@id = id
|
32
|
+
@driver = driver.new(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def hugs
|
36
|
+
@hugs ||= Collection.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def json
|
40
|
+
{
|
41
|
+
id: id,
|
42
|
+
driver: driver.id,
|
43
|
+
uri: "/#{id}"
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
class Hug
|
50
|
+
include Identifier
|
51
|
+
|
52
|
+
attr_reader :datasource, :query
|
53
|
+
|
54
|
+
def initialize(id, datasource, query)
|
55
|
+
@id = id
|
56
|
+
@datasource = datasource
|
57
|
+
@query = query
|
58
|
+
end
|
59
|
+
|
60
|
+
def json
|
61
|
+
{
|
62
|
+
id: id,
|
63
|
+
datasource: datasource.json,
|
64
|
+
uri: "/#{datasource.id}/#{id}"
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def results
|
69
|
+
datasource.driver.query(id, @query)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
class Config
|
75
|
+
|
76
|
+
def initialize(config='./config.yml')
|
77
|
+
yaml = load(config)
|
78
|
+
raise "Invalid YAML file #{config}" unless yaml
|
79
|
+
yaml.each do |id, ds|
|
80
|
+
datasource = Datasource.new(id, driver(ds['driver']), ds['options'])
|
81
|
+
(ds['hugs'] || []).each do |id, query|
|
82
|
+
datasource.hugs << Hug.new( id, datasource, query )
|
83
|
+
end
|
84
|
+
datasources << datasource
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def datasources
|
89
|
+
@datasources ||= Collection.new
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def load(config)
|
94
|
+
YAML.load(File.read(File.expand_path(config)))
|
95
|
+
end
|
96
|
+
|
97
|
+
def driver(id)
|
98
|
+
GrosCalin.drivers[id]
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module GrosCalin
|
2
|
+
|
3
|
+
class << self
|
4
|
+
def drivers
|
5
|
+
@drivers ||= {}
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Driver
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def id
|
17
|
+
self.class.id
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.included(base)
|
21
|
+
base.extend(ClassMethods)
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
|
26
|
+
attr_reader :id
|
27
|
+
|
28
|
+
def register(id)
|
29
|
+
GrosCalin.drivers[@id = id] = self
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
require "gros_calin/mysql"
|
39
|
+
require "gros_calin/mongo_db"
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module GrosCalin
|
2
|
+
|
3
|
+
begin
|
4
|
+
|
5
|
+
require 'moped'
|
6
|
+
|
7
|
+
class MongoDB
|
8
|
+
include Driver
|
9
|
+
|
10
|
+
register 'mongodb'
|
11
|
+
|
12
|
+
def query(id, js)
|
13
|
+
with_session do |session|
|
14
|
+
cmd = {'$eval' => "function(){ return #{js}; }", nolock: true}
|
15
|
+
session.command(cmd)['retval']
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def with_session(&block)
|
22
|
+
session = Moped::Session.new(@options['hosts'] || ['127.0.0.1:27017'])
|
23
|
+
session.use @options['database']
|
24
|
+
if @options['username']
|
25
|
+
session.login(@options['username'], @options['password'])
|
26
|
+
end
|
27
|
+
yield session
|
28
|
+
end
|
29
|
+
|
30
|
+
def mandatory(options, attr)
|
31
|
+
raise "\"#{attr}\" has not been specified" unless options[attr]
|
32
|
+
options[attr]
|
33
|
+
end
|
34
|
+
|
35
|
+
def whitelist(query)
|
36
|
+
query.select{|descriptor|
|
37
|
+
name = descriptor.is_a?(Hash) && descriptor.keys.first || descriptor
|
38
|
+
ALLOWED_METHODS.include?(name)
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
rescue
|
45
|
+
puts "Unable to find the moped gem, driver for MongoDB won't load."
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GrosCalin
|
2
|
+
|
3
|
+
begin
|
4
|
+
|
5
|
+
require 'mysql2'
|
6
|
+
|
7
|
+
class Mysql
|
8
|
+
include Driver
|
9
|
+
register 'mysql'
|
10
|
+
|
11
|
+
def query(id, sql)
|
12
|
+
Mysql2::Client.new(@options).query(sql).each
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
rescue
|
17
|
+
puts "Unable to find the mysql2 gem, driver for MySQL won't load."
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/lib/gros_calin.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require "gros_calin/version"
|
2
|
+
require "gros_calin/config"
|
3
|
+
require "gros_calin/driver"
|
4
|
+
require "sinatra/base"
|
5
|
+
require "sinatra/json"
|
6
|
+
|
7
|
+
module GrosCalin
|
8
|
+
|
9
|
+
class Application < Sinatra::Base
|
10
|
+
helpers Sinatra::JSON
|
11
|
+
|
12
|
+
set :show_exceptions, false
|
13
|
+
|
14
|
+
def config
|
15
|
+
settings.config
|
16
|
+
end
|
17
|
+
|
18
|
+
def datasource(id)
|
19
|
+
config.datasources.get(id).tap do |datasource|
|
20
|
+
unless datasource
|
21
|
+
raise Sinatra::NotFound.new("Unknown datasource with id \"#{id}\"")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def hug(datasource, id)
|
27
|
+
datasource(datasource).hugs.get(id).tap do |hug|
|
28
|
+
unless hug
|
29
|
+
raise Sinatra::NotFound.new("Unknown hug with identifier \"#{id}\" " +
|
30
|
+
"for datasource \"#{datasource}\"")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
not_found do
|
36
|
+
env['sinatra.error'].message
|
37
|
+
end
|
38
|
+
|
39
|
+
error do
|
40
|
+
'Something went wrong: ' + env['sinatra.error'].message
|
41
|
+
end
|
42
|
+
|
43
|
+
# List the available datasources
|
44
|
+
get '/' do
|
45
|
+
json config.datasources.json
|
46
|
+
end
|
47
|
+
|
48
|
+
# Show the details and available hugs for a given datasource
|
49
|
+
get '/:datasource' do
|
50
|
+
json datasource(params[:datasource]).hugs.map(&:json)
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Query a specific hug
|
55
|
+
get '/:datasource/:hug' do
|
56
|
+
json hug(params[:datasource], params[:hug]).results
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/romain-gary.jpg
ADDED
Binary file
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrosCalin::Collection do
|
4
|
+
|
5
|
+
let(:collection){ subject.new }
|
6
|
+
|
7
|
+
describe 'retrieving items by id' do
|
8
|
+
|
9
|
+
it 'finds the item' do
|
10
|
+
collection << mock(id: 1)
|
11
|
+
collection << item = mock(id: 2)
|
12
|
+
collection.get(2).must_equal item
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'ignores items which do not respond to id' do
|
16
|
+
collection << mock
|
17
|
+
collection << item = mock(id: 2)
|
18
|
+
collection.get(2).must_equal item
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'includes children when building a serializable hash' do
|
24
|
+
collection << mock(json: { id: 1 })
|
25
|
+
collection.json.must_equal [{id: 1}]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
ConfigDriverKlazz = Class.new do
|
31
|
+
include GrosCalin::Driver
|
32
|
+
|
33
|
+
register 'driver_id'
|
34
|
+
end
|
35
|
+
|
36
|
+
describe GrosCalin::Datasource do
|
37
|
+
|
38
|
+
let(:datasource){
|
39
|
+
GrosCalin::Datasource.new('dsid', ConfigDriverKlazz, {an_option: 1})
|
40
|
+
}
|
41
|
+
|
42
|
+
let(:datasource_hash){
|
43
|
+
{id: 'dsid', driver: 'driver_id', uri: '/dsid'}
|
44
|
+
}
|
45
|
+
|
46
|
+
it 'initializes the driver with options' do
|
47
|
+
datasource.driver.must_be_instance_of ConfigDriverKlazz
|
48
|
+
datasource.driver.options.must_equal( an_option: 1 )
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'creates an empty hugs collection' do
|
52
|
+
datasource.hugs.must_be_instance_of GrosCalin::Collection
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'builds a serializable hash' do
|
56
|
+
datasource.json.must_equal(datasource_hash)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
describe GrosCalin::Hug do
|
61
|
+
|
62
|
+
let(:hug){ subject.new('hugid', datasource, 'select') }
|
63
|
+
|
64
|
+
it 'builds a serializable hash' do
|
65
|
+
hug.json.must_equal( id: 'hugid', datasource: datasource_hash,
|
66
|
+
uri: '/dsid/hugid' )
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'queries the driver' do
|
70
|
+
datasource.driver.expects(:query).with('hugid', 'select').
|
71
|
+
returns(results=[])
|
72
|
+
hug.results.must_equal results
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe GrosCalin::Config do
|
80
|
+
|
81
|
+
let(:empty_file) do
|
82
|
+
f = Tempfile.new('config.yml')
|
83
|
+
f.close
|
84
|
+
f
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:config_file) do
|
88
|
+
f = Tempfile.new('config.yml')
|
89
|
+
f.write <<-EOF
|
90
|
+
---
|
91
|
+
dsid:
|
92
|
+
driver: "driver_id"
|
93
|
+
options:
|
94
|
+
username: "user"
|
95
|
+
hugs:
|
96
|
+
all: "select"
|
97
|
+
EOF
|
98
|
+
f.close
|
99
|
+
f
|
100
|
+
end
|
101
|
+
|
102
|
+
after do
|
103
|
+
[config_file, empty_file].each(&:unlink)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'defaults to config.yml' do
|
107
|
+
subject.any_instance.expects(:load).with('./config.yml').returns([])
|
108
|
+
subject.new
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'raises if the config file does not exist' do
|
112
|
+
->{ subject.new('absent.yml')}.must_raise Errno::ENOENT
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'raises if the config file does not exist' do
|
116
|
+
ex = ->{ subject.new(empty_file)}.must_raise RuntimeError
|
117
|
+
ex.message.must_equal "Invalid YAML file #{empty_file}"
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'loads the provided configuration' do
|
121
|
+
config = subject.new(config_file)
|
122
|
+
ds = config.datasources.length.must_equal 1
|
123
|
+
ds = config.datasources.first
|
124
|
+
ds.id.must_equal 'dsid'
|
125
|
+
ds.driver.must_be_instance_of ConfigDriverKlazz
|
126
|
+
ds.driver.options['username'].must_equal "user"
|
127
|
+
ds.hugs.length.must_equal 1
|
128
|
+
hug = ds.hugs.first
|
129
|
+
hug.id.must_equal 'all'
|
130
|
+
hug.datasource.must_equal ds
|
131
|
+
hug.query.must_equal 'select'
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrosCalin::Driver do
|
4
|
+
|
5
|
+
DriverKlazz = Class.new do
|
6
|
+
include GrosCalin::Driver
|
7
|
+
|
8
|
+
register 'test_driver'
|
9
|
+
end
|
10
|
+
|
11
|
+
describe DriverKlazz do
|
12
|
+
|
13
|
+
it 'uses the id it registered with' do
|
14
|
+
subject.new.id.must_equal 'test_driver'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'exposes its initialization options' do
|
18
|
+
subject.new(options={an_option: 1}).options.must_equal options
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrosCalin::MongoDB do
|
4
|
+
|
5
|
+
it 'registered as mongodb' do
|
6
|
+
GrosCalin.drivers['mongodb'].must_equal subject
|
7
|
+
end
|
8
|
+
|
9
|
+
def expects_session(hosts=['127.0.0.1:27017'])
|
10
|
+
::Moped::Session.expects(:new).with(hosts).
|
11
|
+
returns(session=mock)
|
12
|
+
session.expects(:use).with('db')
|
13
|
+
session
|
14
|
+
end
|
15
|
+
|
16
|
+
def ensure_session_yielded(options={})
|
17
|
+
session = nil
|
18
|
+
subject.new(options.merge('database'=> 'db')).send(:with_session) do |s|
|
19
|
+
session = s
|
20
|
+
end
|
21
|
+
session.wont_be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'defaults to localhost' do
|
25
|
+
expects_session
|
26
|
+
ensure_session_yielded
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'uses the provided hosts' do
|
30
|
+
expects_session( hosts = ['host.tld:27018'] )
|
31
|
+
ensure_session_yielded('hosts'=>hosts)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'logs in if a username was provided' do
|
35
|
+
session = expects_session ['127.0.0.1:27017']
|
36
|
+
session.expects(:login).with('user', 'secret')
|
37
|
+
ensure_session_yielded('username'=>'user', 'password'=>'secret')
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'queries the database' do
|
41
|
+
session = expects_session ['127.0.0.1:27017']
|
42
|
+
js = 'db.collection.find().toArray()'
|
43
|
+
session.expects(:command).
|
44
|
+
with('$eval' => "function(){ return #{js}; }", nolock: true).
|
45
|
+
returns({ 'retval'=>ary=[] })
|
46
|
+
subject.new({ 'database' => 'db' }).query('id', js).must_equal ary
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrosCalin::Mysql do
|
4
|
+
|
5
|
+
it 'registered as mysql' do
|
6
|
+
GrosCalin.drivers['mysql'].must_equal subject
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'queries the database' do
|
10
|
+
Mysql2::Client.expects(:new).with(options={an_option: 1}).
|
11
|
+
returns(client=mock)
|
12
|
+
client.expects(:query).with('select').returns(result=mock)
|
13
|
+
result.expects(:each).returns(data=[])
|
14
|
+
subject.new(options).query('id', 'select').must_equal data
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rack/test'
|
3
|
+
|
4
|
+
describe GrosCalin::Application do
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
let(:config){ mock }
|
8
|
+
let(:data){ { key: 'value' } }
|
9
|
+
let(:body){ '{"key":"value"}' }
|
10
|
+
|
11
|
+
def app
|
12
|
+
subject.set :config, config
|
13
|
+
subject
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'renders the error message on error' do
|
17
|
+
config.expects(:datasources).raises(RuntimeError, "That's an error")
|
18
|
+
get '/'
|
19
|
+
last_response.status.must_equal 500
|
20
|
+
last_response.body.must_equal "Something went wrong: That's an error"
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'lists datasources' do
|
24
|
+
config.expects(:datasources).returns(mock(json: data))
|
25
|
+
get '/'
|
26
|
+
last_response.status.must_equal 200
|
27
|
+
last_response.body.must_equal body
|
28
|
+
end
|
29
|
+
|
30
|
+
def datasources
|
31
|
+
config.expects(:datasources).returns(datasources=mock)
|
32
|
+
datasources
|
33
|
+
end
|
34
|
+
|
35
|
+
def expects_404(collection, param, url, error_message)
|
36
|
+
collection.expects(:get).with(param).returns(nil)
|
37
|
+
get url
|
38
|
+
last_response.status.must_equal 404
|
39
|
+
last_response.body.must_match error_message
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'renders a 404 when it fails to find a specific datasource' do
|
43
|
+
expects_404(datasources, 'dsid', '/dsid', /^Unknown datasource/)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'with a specific datasource' do
|
47
|
+
|
48
|
+
let(:datasource){ mock }
|
49
|
+
|
50
|
+
before do
|
51
|
+
datasources.expects(:get).with('dsid').returns(datasource)
|
52
|
+
end
|
53
|
+
|
54
|
+
def ensure_json_array
|
55
|
+
last_response.status.must_equal 200
|
56
|
+
last_response.body.must_equal "[#{body}]"
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'shows the list of hugs for a datasource' do
|
60
|
+
datasource.expects(:hugs).returns([mock(json: data)])
|
61
|
+
get '/dsid'
|
62
|
+
ensure_json_array
|
63
|
+
end
|
64
|
+
|
65
|
+
def hugs
|
66
|
+
datasource.expects(:hugs).returns(hugs=mock)
|
67
|
+
hugs
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'renders a specific hug' do
|
71
|
+
hugs.expects(:get).with('hugid').returns(mock(results: [data]))
|
72
|
+
get '/dsid/hugid'
|
73
|
+
ensure_json_array
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'renders a 404 when it fails to find a specific hug' do
|
77
|
+
expects_404(hugs, 'hugid', '/dsid/hugid', /^Unknown hug/)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter
|
7
|
+
]
|
8
|
+
|
9
|
+
SimpleCov.start do
|
10
|
+
add_filter '/spec/'
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'gros_calin'
|
14
|
+
require 'minitest'
|
15
|
+
require 'minitest/spec'
|
16
|
+
require 'minitest/autorun'
|
17
|
+
require 'minitest/pride'
|
18
|
+
require 'minitest-implicit-subject'
|
19
|
+
require 'mocha/setup'
|
20
|
+
|
21
|
+
GrosCalin::Application.set :raise_errors, false
|
metadata
ADDED
@@ -0,0 +1,383 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gros_calin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jef Mathiot
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-20 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.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mocha
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 1.1.0
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '1.1'
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.1.0
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: coveralls
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0.7'
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.7.1
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.7'
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 0.7.1
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: minitest
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '5.4'
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 5.4.1
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '5.4'
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: 5.4.1
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
name: minitest-implicit-subject
|
103
|
+
requirement: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - "~>"
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '1.4'
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.4.0
|
111
|
+
type: :development
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.4'
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 1.4.0
|
121
|
+
- !ruby/object:Gem::Dependency
|
122
|
+
name: rb-readline
|
123
|
+
requirement: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - "~>"
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0.5'
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 0.5.0
|
131
|
+
type: :development
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0.5'
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: 0.5.0
|
141
|
+
- !ruby/object:Gem::Dependency
|
142
|
+
name: guard
|
143
|
+
requirement: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - "~>"
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '2.11'
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: 2.11.1
|
151
|
+
type: :development
|
152
|
+
prerelease: false
|
153
|
+
version_requirements: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - "~>"
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '2.11'
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: 2.11.1
|
161
|
+
- !ruby/object:Gem::Dependency
|
162
|
+
name: guard-minitest
|
163
|
+
requirement: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '2.3'
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: 2.3.2
|
171
|
+
type: :development
|
172
|
+
prerelease: false
|
173
|
+
version_requirements: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - "~>"
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '2.3'
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 2.3.2
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: mysql2
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0.3'
|
188
|
+
- - ">="
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: 0.3.18
|
191
|
+
type: :development
|
192
|
+
prerelease: false
|
193
|
+
version_requirements: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - "~>"
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0.3'
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: 0.3.18
|
201
|
+
- !ruby/object:Gem::Dependency
|
202
|
+
name: moped
|
203
|
+
requirement: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - "~>"
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: '2.0'
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: 2.0.3
|
211
|
+
type: :development
|
212
|
+
prerelease: false
|
213
|
+
version_requirements: !ruby/object:Gem::Requirement
|
214
|
+
requirements:
|
215
|
+
- - "~>"
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '2.0'
|
218
|
+
- - ">="
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: 2.0.3
|
221
|
+
- !ruby/object:Gem::Dependency
|
222
|
+
name: sinatra
|
223
|
+
requirement: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - "~>"
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '1.4'
|
228
|
+
- - ">="
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
version: 1.4.5
|
231
|
+
type: :runtime
|
232
|
+
prerelease: false
|
233
|
+
version_requirements: !ruby/object:Gem::Requirement
|
234
|
+
requirements:
|
235
|
+
- - "~>"
|
236
|
+
- !ruby/object:Gem::Version
|
237
|
+
version: '1.4'
|
238
|
+
- - ">="
|
239
|
+
- !ruby/object:Gem::Version
|
240
|
+
version: 1.4.5
|
241
|
+
- !ruby/object:Gem::Dependency
|
242
|
+
name: sinatra-contrib
|
243
|
+
requirement: !ruby/object:Gem::Requirement
|
244
|
+
requirements:
|
245
|
+
- - "~>"
|
246
|
+
- !ruby/object:Gem::Version
|
247
|
+
version: '1.4'
|
248
|
+
- - ">="
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: 1.4.2
|
251
|
+
type: :runtime
|
252
|
+
prerelease: false
|
253
|
+
version_requirements: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - "~>"
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '1.4'
|
258
|
+
- - ">="
|
259
|
+
- !ruby/object:Gem::Version
|
260
|
+
version: 1.4.2
|
261
|
+
- !ruby/object:Gem::Dependency
|
262
|
+
name: rack
|
263
|
+
requirement: !ruby/object:Gem::Requirement
|
264
|
+
requirements:
|
265
|
+
- - "~>"
|
266
|
+
- !ruby/object:Gem::Version
|
267
|
+
version: '1.6'
|
268
|
+
- - ">="
|
269
|
+
- !ruby/object:Gem::Version
|
270
|
+
version: 1.6.0
|
271
|
+
type: :runtime
|
272
|
+
prerelease: false
|
273
|
+
version_requirements: !ruby/object:Gem::Requirement
|
274
|
+
requirements:
|
275
|
+
- - "~>"
|
276
|
+
- !ruby/object:Gem::Version
|
277
|
+
version: '1.6'
|
278
|
+
- - ">="
|
279
|
+
- !ruby/object:Gem::Version
|
280
|
+
version: 1.6.0
|
281
|
+
- !ruby/object:Gem::Dependency
|
282
|
+
name: thin
|
283
|
+
requirement: !ruby/object:Gem::Requirement
|
284
|
+
requirements:
|
285
|
+
- - "~>"
|
286
|
+
- !ruby/object:Gem::Version
|
287
|
+
version: '1.6'
|
288
|
+
- - ">="
|
289
|
+
- !ruby/object:Gem::Version
|
290
|
+
version: 1.6.3
|
291
|
+
type: :runtime
|
292
|
+
prerelease: false
|
293
|
+
version_requirements: !ruby/object:Gem::Requirement
|
294
|
+
requirements:
|
295
|
+
- - "~>"
|
296
|
+
- !ruby/object:Gem::Version
|
297
|
+
version: '1.6'
|
298
|
+
- - ">="
|
299
|
+
- !ruby/object:Gem::Version
|
300
|
+
version: 1.6.3
|
301
|
+
- !ruby/object:Gem::Dependency
|
302
|
+
name: thor
|
303
|
+
requirement: !ruby/object:Gem::Requirement
|
304
|
+
requirements:
|
305
|
+
- - "~>"
|
306
|
+
- !ruby/object:Gem::Version
|
307
|
+
version: '0.19'
|
308
|
+
- - ">="
|
309
|
+
- !ruby/object:Gem::Version
|
310
|
+
version: 0.19.1
|
311
|
+
type: :runtime
|
312
|
+
prerelease: false
|
313
|
+
version_requirements: !ruby/object:Gem::Requirement
|
314
|
+
requirements:
|
315
|
+
- - "~>"
|
316
|
+
- !ruby/object:Gem::Version
|
317
|
+
version: '0.19'
|
318
|
+
- - ">="
|
319
|
+
- !ruby/object:Gem::Version
|
320
|
+
version: 0.19.1
|
321
|
+
description: Make database queries available via HTTP
|
322
|
+
email:
|
323
|
+
- jeff.mathiot@gmail.com
|
324
|
+
executables:
|
325
|
+
- gros_calin
|
326
|
+
extensions: []
|
327
|
+
extra_rdoc_files: []
|
328
|
+
files:
|
329
|
+
- ".gitignore"
|
330
|
+
- ".travis.yml"
|
331
|
+
- Gemfile
|
332
|
+
- Guardfile
|
333
|
+
- LICENSE.txt
|
334
|
+
- README.md
|
335
|
+
- Rakefile
|
336
|
+
- bin/gros_calin
|
337
|
+
- config.ru
|
338
|
+
- gros_calin.gemspec
|
339
|
+
- lib/gros_calin.rb
|
340
|
+
- lib/gros_calin/cli.rb
|
341
|
+
- lib/gros_calin/config.rb
|
342
|
+
- lib/gros_calin/driver.rb
|
343
|
+
- lib/gros_calin/mongo_db.rb
|
344
|
+
- lib/gros_calin/mysql.rb
|
345
|
+
- lib/gros_calin/version.rb
|
346
|
+
- romain-gary.jpg
|
347
|
+
- spec/gros_calin/config_spec.rb
|
348
|
+
- spec/gros_calin/driver_spec.rb
|
349
|
+
- spec/gros_calin/mongodb_spec.rb
|
350
|
+
- spec/gros_calin/mysql_spec.rb
|
351
|
+
- spec/gros_calin_spec.rb
|
352
|
+
- spec/spec_helper.rb
|
353
|
+
homepage: https://github.com/servebox/gros_calin
|
354
|
+
licenses:
|
355
|
+
- MIT
|
356
|
+
metadata: {}
|
357
|
+
post_install_message:
|
358
|
+
rdoc_options: []
|
359
|
+
require_paths:
|
360
|
+
- lib
|
361
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
362
|
+
requirements:
|
363
|
+
- - ">="
|
364
|
+
- !ruby/object:Gem::Version
|
365
|
+
version: '0'
|
366
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
367
|
+
requirements:
|
368
|
+
- - ">="
|
369
|
+
- !ruby/object:Gem::Version
|
370
|
+
version: '0'
|
371
|
+
requirements: []
|
372
|
+
rubyforge_project:
|
373
|
+
rubygems_version: 2.2.2
|
374
|
+
signing_key:
|
375
|
+
specification_version: 4
|
376
|
+
summary: Make database queries available via HTTP
|
377
|
+
test_files:
|
378
|
+
- spec/gros_calin/config_spec.rb
|
379
|
+
- spec/gros_calin/driver_spec.rb
|
380
|
+
- spec/gros_calin/mongodb_spec.rb
|
381
|
+
- spec/gros_calin/mysql_spec.rb
|
382
|
+
- spec/gros_calin_spec.rb
|
383
|
+
- spec/spec_helper.rb
|