nobrainer 0.22.0 → 0.23.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 +4 -4
- data/lib/no_brainer/criteria/enumerable.rb +2 -0
- data/lib/no_brainer/criteria/where.rb +2 -1
- data/lib/no_brainer/document/association/belongs_to.rb +23 -11
- data/lib/no_brainer/document/association/has_many.rb +3 -6
- data/lib/no_brainer/document/dirty.rb +3 -1
- data/lib/no_brainer/locale/en.yml +1 -0
- data/lib/no_brainer/{query_runner/logger.rb → logger.rb} +6 -21
- data/lib/no_brainer/profiler.rb +11 -0
- data/lib/no_brainer/profiler/controller_runtime.rb +76 -0
- data/lib/no_brainer/profiler/logger.rb +46 -0
- data/lib/no_brainer/query_runner.rb +3 -3
- data/lib/no_brainer/query_runner/profiler.rb +42 -0
- data/lib/no_brainer/railtie.rb +5 -0
- data/lib/no_brainer/rql.rb +3 -1
- data/lib/nobrainer.rb +2 -1
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f77c9211fbf5a8c8fb7a695542b862cfd693ed82
|
4
|
+
data.tar.gz: 72bd41593dfbb997eb1dd72a70c00c08f75f4124
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd5ca8440015b18adfc34f61bb7862e15bc445a459cf1c2310843c3c7194862f1d1abecd72c4ce14a7501a6345704fea20f49b332331b227d8ee0309494a36bb
|
7
|
+
data.tar.gz: cd4d1d5b1e8cb9ee69eed9b6a0956626e407fd3e1c1bf9e60bedd502def6c0adbe8684826afde573dde490ae6db0842cb602eb03b2025166780574bb17c474a5
|
@@ -401,7 +401,8 @@ module NoBrainer::Criteria::Where
|
|
401
401
|
options[:right_bound] = {:lt => :open, :le => :closed}[right_bound.op] if right_bound
|
402
402
|
|
403
403
|
return IndexStrategy.new(self, ast, [left_bound, right_bound].compact, index, :between,
|
404
|
-
[left_bound.try(:value)
|
404
|
+
[left_bound ? left_bound.try(:value) : RethinkDB::RQL.new.minval,
|
405
|
+
right_bound ? right_bound.try(:value) : RethinkDB::RQL.new.maxval], options)
|
405
406
|
end
|
406
407
|
return nil
|
407
408
|
end
|
@@ -7,17 +7,14 @@ class NoBrainer::Document::Association::BelongsTo
|
|
7
7
|
extend NoBrainer::Document::Association::EagerLoader::Generic
|
8
8
|
|
9
9
|
def foreign_key
|
10
|
-
# TODO test :foreign_key
|
11
10
|
options[:foreign_key].try(:to_sym) || :"#{target_name}_#{primary_key}"
|
12
11
|
end
|
13
12
|
|
14
13
|
def primary_key
|
15
|
-
# TODO test :primary_key
|
16
14
|
options[:primary_key].try(:to_sym) || target_model.pk_name
|
17
15
|
end
|
18
16
|
|
19
17
|
def target_model
|
20
|
-
# TODO test :class_name
|
21
18
|
(options[:class_name] || target_name.to_s.camelize).constantize
|
22
19
|
end
|
23
20
|
|
@@ -27,15 +24,30 @@ class NoBrainer::Document::Association::BelongsTo
|
|
27
24
|
|
28
25
|
def hook
|
29
26
|
super
|
27
|
+
# XXX We are loading the target_model unless the primary_key is not
|
28
|
+
# specified. This may eager load a part of the application.
|
29
|
+
# Oh well.
|
30
30
|
|
31
|
-
# TODO
|
32
|
-
#
|
33
|
-
|
34
|
-
#
|
35
|
-
# of the primary key of the target.
|
31
|
+
# TODO if the primary key of the target_model changes, we need to revisit
|
32
|
+
# our default foreign_key/primary_key value
|
33
|
+
|
34
|
+
# TODO set the type of the foreign key to be the same as the target's primary key
|
36
35
|
owner_model.field(foreign_key, :store_as => options[:foreign_key_store_as], :index => options[:index])
|
37
|
-
|
38
|
-
|
36
|
+
|
37
|
+
unless options[:validates] == false
|
38
|
+
owner_model.validates(target_name, options[:validates]) if options[:validates]
|
39
|
+
|
40
|
+
if options[:required]
|
41
|
+
owner_model.validates(target_name, :presence => options[:required])
|
42
|
+
else
|
43
|
+
# Always validate the validity of the foreign_key if not nil.
|
44
|
+
owner_model.validates_each(foreign_key) do |doc, attr, value|
|
45
|
+
if !value.nil? && doc.read_attribute_for_validation(target_name).nil?
|
46
|
+
doc.errors.add(attr, :invalid_foreign_key, :target_model => target_model, :primary_key => primary_key)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
39
51
|
|
40
52
|
delegate("#{foreign_key}=", :assign_foreign_key, :call_super => true)
|
41
53
|
delegate("#{target_name}_changed?", "#{foreign_key}_changed?", :to => :self)
|
@@ -64,7 +76,7 @@ class NoBrainer::Document::Association::BelongsTo
|
|
64
76
|
|
65
77
|
def write(target)
|
66
78
|
assert_target_type(target)
|
67
|
-
owner.write_attribute(foreign_key, target.try(
|
79
|
+
owner.write_attribute(foreign_key, target.try(primary_key))
|
68
80
|
preload(target)
|
69
81
|
end
|
70
82
|
|
@@ -7,17 +7,14 @@ class NoBrainer::Document::Association::HasMany
|
|
7
7
|
extend NoBrainer::Document::Association::EagerLoader::Generic
|
8
8
|
|
9
9
|
def foreign_key
|
10
|
-
|
11
|
-
options[:foreign_key].try(:to_sym) || :"#{owner_model.name.underscore}_#{owner_model.pk_name}"
|
10
|
+
options[:foreign_key].try(:to_sym) || :"#{owner_model.name.underscore}_#{primary_key}"
|
12
11
|
end
|
13
12
|
|
14
13
|
def primary_key
|
15
|
-
|
16
|
-
options[:primary_key].try(:to_sym) || target_model.pk_name
|
14
|
+
options[:primary_key].try(:to_sym) || owner_model.pk_name
|
17
15
|
end
|
18
16
|
|
19
17
|
def target_model
|
20
|
-
# TODO test :class_name
|
21
18
|
(options[:class_name] || target_name.to_s.singularize.camelize).constantize
|
22
19
|
end
|
23
20
|
|
@@ -60,7 +57,7 @@ class NoBrainer::Document::Association::HasMany
|
|
60
57
|
end
|
61
58
|
|
62
59
|
def target_criteria
|
63
|
-
@target_criteria ||= base_criteria.where(foreign_key => owner.
|
60
|
+
@target_criteria ||= base_criteria.where(foreign_key => owner.__send__(primary_key))
|
64
61
|
.after_find(set_inverse_proc)
|
65
62
|
end
|
66
63
|
|
@@ -17,7 +17,9 @@ module NoBrainer::Document::Dirty
|
|
17
17
|
def clear_dirtiness(options={})
|
18
18
|
if options[:keep_ivars] && options[:missing_attributes].try(:[], :pluck)
|
19
19
|
attrs = options[:missing_attributes][:pluck].keys
|
20
|
-
@_old_attributes = @_old_attributes.reject { |k,v| attrs.include?(k) }
|
20
|
+
@_old_attributes = @_old_attributes.reject { |k,v| attrs.include?(k) }
|
21
|
+
else
|
22
|
+
@_old_attributes = {}.with_indifferent_access
|
21
23
|
end
|
22
24
|
|
23
25
|
@_old_attributes_keys = @_attributes.keys # to track undefined -> nil changes
|
@@ -1,16 +1,9 @@
|
|
1
|
-
class NoBrainer::
|
2
|
-
def
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
raise e
|
8
|
-
end
|
9
|
-
|
10
|
-
private
|
11
|
-
|
12
|
-
def log_query(env, start_time, exception=nil)
|
13
|
-
return if handle_on_demand_exception?(env, exception)
|
1
|
+
class NoBrainer::Logger
|
2
|
+
def on_query(env)
|
3
|
+
# env[:end_time] = Time.now
|
4
|
+
# env[:duration] = env[:end_time] - env[:start_time]
|
5
|
+
# env[:exception] = exception
|
6
|
+
# env[:query_type] = NoBrainer::RQL.type_of(env[:query])
|
14
7
|
|
15
8
|
not_indexed = env[:criteria] && env[:criteria].where_present? &&
|
16
9
|
!env[:criteria].where_indexed? &&
|
@@ -20,8 +13,6 @@ class NoBrainer::QueryRunner::Logger < NoBrainer::QueryRunner::Middleware
|
|
20
13
|
not_indexed ? Logger::INFO : Logger::DEBUG
|
21
14
|
return if NoBrainer.logger.nil? || NoBrainer.logger.level > level
|
22
15
|
|
23
|
-
duration = Time.now - start_time
|
24
|
-
|
25
16
|
msg_duration = (duration * 1000.0).round(1).to_s
|
26
17
|
msg_duration = " " * [0, 6 - msg_duration.size].max + msg_duration
|
27
18
|
msg_duration = "[#{msg_duration}ms] "
|
@@ -52,10 +43,4 @@ class NoBrainer::QueryRunner::Logger < NoBrainer::QueryRunner::Middleware
|
|
52
43
|
msg = [msg_duration, msg_db, msg_query, msg_exception, msg_last].join
|
53
44
|
NoBrainer.logger.add(level, msg)
|
54
45
|
end
|
55
|
-
|
56
|
-
def handle_on_demand_exception?(env, e)
|
57
|
-
# pretty gross I must say.
|
58
|
-
e && (NoBrainer::QueryRunner::DatabaseOnDemand.new(nil).handle_database_on_demand_exception?(env, e) ||
|
59
|
-
NoBrainer::QueryRunner::TableOnDemand.new(nil).handle_table_on_demand_exception?(env, e))
|
60
|
-
end
|
61
46
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Rails specific. TODO Test
|
2
|
+
module NoBrainer::Profiler::ControllerRuntime
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class Profiler
|
6
|
+
attr_accessor :write_duration, :read_duration, :other_duration
|
7
|
+
def initialize
|
8
|
+
@write_duration = @read_duration = @other_duration = 0.0
|
9
|
+
end
|
10
|
+
|
11
|
+
def total_duration
|
12
|
+
read_duration + write_duration + other_duration
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_query(env)
|
16
|
+
case env[:query_type]
|
17
|
+
when :write then @write_duration += env[:duration]
|
18
|
+
when :read then @read_duration += env[:duration]
|
19
|
+
else @other_duration += env[:duration]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.spawn_controller_profiler
|
24
|
+
Thread.current[:nobrainer_controller_profiler] = new
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.cleanup_controller_profiler
|
28
|
+
Thread.current[:nobrainer_controller_profiler] = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.current
|
32
|
+
Thread.current[:nobrainer_controller_profiler]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.on_query(env)
|
36
|
+
current.try(:add_query, env)
|
37
|
+
end
|
38
|
+
|
39
|
+
NoBrainer::Profiler.register(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_action(action, *args)
|
43
|
+
Profiler.spawn_controller_profiler
|
44
|
+
super
|
45
|
+
ensure
|
46
|
+
Profiler.cleanup_controller_profiler
|
47
|
+
end
|
48
|
+
|
49
|
+
def cleanup_view_runtime
|
50
|
+
time_spent_in_db_before_views = Profiler.current.total_duration
|
51
|
+
runtime = super
|
52
|
+
time_spent_in_db_after_views = Profiler.current.total_duration
|
53
|
+
|
54
|
+
time_spent_in_db_during_views = (time_spent_in_db_after_views - time_spent_in_db_before_views) * 1000
|
55
|
+
runtime - time_spent_in_db_during_views
|
56
|
+
end
|
57
|
+
|
58
|
+
def append_info_to_payload(payload)
|
59
|
+
super
|
60
|
+
payload[:nobrainer_profiler] = Profiler.current
|
61
|
+
end
|
62
|
+
|
63
|
+
module ClassMethods # :nodoc:
|
64
|
+
def log_process_action(payload)
|
65
|
+
messages, profiler = super, payload[:nobrainer_profiler]
|
66
|
+
if profiler && !profiler.total_duration.zero?
|
67
|
+
msg = []
|
68
|
+
msg << "%.1fms (write)" % (profiler.write_duration * 1000) unless profiler.write_duration.zero?
|
69
|
+
msg << "%.1fms (read)" % (profiler.read_duration * 1000) unless profiler.read_duration.zero?
|
70
|
+
msg << "%.1fms (other)" % (profiler.other_duration * 1000) unless profiler.other_duration.zero?
|
71
|
+
messages << "NoBrainer: #{msg.join(", ")}"
|
72
|
+
end
|
73
|
+
messages
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class NoBrainer::Profiler::Logger
|
2
|
+
def on_query(env)
|
3
|
+
not_indexed = env[:criteria] && env[:criteria].where_present? &&
|
4
|
+
!env[:criteria].where_indexed? &&
|
5
|
+
!env[:criteria].model.try(:perf_warnings_disabled)
|
6
|
+
|
7
|
+
level = env[:exception] ? Logger::ERROR :
|
8
|
+
not_indexed ? Logger::INFO : Logger::DEBUG
|
9
|
+
return if NoBrainer.logger.nil? || NoBrainer.logger.level > level
|
10
|
+
|
11
|
+
msg_duration = (env[:duration] * 1000.0).round(1).to_s
|
12
|
+
msg_duration = " " * [0, 6 - msg_duration.size].max + msg_duration
|
13
|
+
msg_duration = "[#{msg_duration}ms] "
|
14
|
+
|
15
|
+
env[:query_type] = NoBrainer::RQL.type_of(env[:query])
|
16
|
+
env[:custom_db_name] = env[:db_name] if env[:db_name].to_s != NoBrainer.connection.parsed_uri[:db]
|
17
|
+
|
18
|
+
msg_db = "[#{env[:custom_db_name]}] " if env[:custom_db_name]
|
19
|
+
msg_query = env[:query].inspect.gsub(/\n/, '').gsub(/ +/, ' ')
|
20
|
+
|
21
|
+
msg_exception = "#{env[:exception].class} #{env[:exception].message.split("\n").first}" if env[:exception]
|
22
|
+
msg_exception ||= "perf: filtering without using an index" if not_indexed
|
23
|
+
|
24
|
+
msg_last = nil
|
25
|
+
|
26
|
+
if NoBrainer::Config.colorize_logger
|
27
|
+
query_color = case env[:query_type]
|
28
|
+
when :write then "\e[1;31m" # red
|
29
|
+
when :read then "\e[1;32m" # green
|
30
|
+
when :management then "\e[1;33m" # yellow
|
31
|
+
end
|
32
|
+
msg_duration = [query_color, msg_duration].join
|
33
|
+
msg_db = ["\e[0;34m", msg_db, query_color].join if msg_db
|
34
|
+
if msg_exception
|
35
|
+
exception_color = "\e[0;31m" if level == Logger::ERROR
|
36
|
+
msg_exception = ["\e[0;39m", " -- ", exception_color, msg_exception].compact.join
|
37
|
+
end
|
38
|
+
msg_last = "\e[0m"
|
39
|
+
end
|
40
|
+
|
41
|
+
msg = [msg_duration, msg_db, msg_query, msg_exception, msg_last].join
|
42
|
+
NoBrainer.logger.add(level, msg)
|
43
|
+
end
|
44
|
+
|
45
|
+
NoBrainer::Profiler.register(self.new)
|
46
|
+
end
|
@@ -11,7 +11,7 @@ module NoBrainer::QueryRunner
|
|
11
11
|
end
|
12
12
|
|
13
13
|
autoload :Driver, :DatabaseOnDemand, :TableOnDemand, :WriteError,
|
14
|
-
:Reconnect, :Selection, :RunOptions, :
|
14
|
+
:Reconnect, :Selection, :RunOptions, :Profiler, :MissingIndex,
|
15
15
|
:ConnectionLock
|
16
16
|
|
17
17
|
class << self
|
@@ -28,11 +28,11 @@ module NoBrainer::QueryRunner
|
|
28
28
|
# thread-safe, since require() is ran with a mutex.
|
29
29
|
self.stack = ::Middleware::Builder.new do
|
30
30
|
use RunOptions
|
31
|
-
use WriteError
|
32
31
|
use MissingIndex
|
33
32
|
use DatabaseOnDemand
|
34
33
|
use TableOnDemand
|
35
|
-
use
|
34
|
+
use Profiler
|
35
|
+
use WriteError
|
36
36
|
use ConnectionLock
|
37
37
|
use Reconnect
|
38
38
|
use Driver
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class NoBrainer::QueryRunner::Profiler < NoBrainer::QueryRunner::Middleware
|
2
|
+
def call(env)
|
3
|
+
profiler_start(env)
|
4
|
+
@runner.call(env).tap { profiler_end(env) }
|
5
|
+
rescue Exception => e
|
6
|
+
profiler_end(env, e)
|
7
|
+
raise e
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def profiler_start(env)
|
13
|
+
env[:start_time] = Time.now
|
14
|
+
end
|
15
|
+
|
16
|
+
def profiler_end(env, exception=nil)
|
17
|
+
return if handle_on_demand_exception?(env, exception)
|
18
|
+
|
19
|
+
env[:end_time] = Time.now
|
20
|
+
env[:duration] = env[:end_time] - env[:start_time]
|
21
|
+
env[:exception] = exception
|
22
|
+
|
23
|
+
env[:model] = env[:criteria] && env[:criteria].model
|
24
|
+
env[:query_type] = NoBrainer::RQL.type_of(env[:query])
|
25
|
+
env[:custom_db_name] = env[:db_name] if env[:db_name] && env[:db_name].to_s != NoBrainer.connection.parsed_uri[:db]
|
26
|
+
|
27
|
+
NoBrainer::Profiler.registered_profilers.each do |profiler|
|
28
|
+
begin
|
29
|
+
profiler.on_query(env)
|
30
|
+
rescue Exception => e
|
31
|
+
STDERR.puts "[NoBrainer] Profiling error: #{e.class} #{e.message}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle_on_demand_exception?(env, e)
|
37
|
+
# pretty gross I must say.
|
38
|
+
e && (NoBrainer::QueryRunner::DatabaseOnDemand.new(nil).handle_database_on_demand_exception?(env, e) ||
|
39
|
+
NoBrainer::QueryRunner::TableOnDemand.new(nil).handle_table_on_demand_exception?(env, e))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
data/lib/no_brainer/railtie.rb
CHANGED
data/lib/no_brainer/rql.rb
CHANGED
@@ -8,7 +8,9 @@ module NoBrainer::RQL
|
|
8
8
|
|
9
9
|
def rql_proc_as_json(block)
|
10
10
|
reset_lambda_var_counter
|
11
|
-
RethinkDB::
|
11
|
+
RethinkDB::Shim.load_json(
|
12
|
+
RethinkDB::Shim.dump_json(
|
13
|
+
RethinkDB::RQL.new.new_func(&block)))
|
12
14
|
end
|
13
15
|
|
14
16
|
def is_write_query?(rql_query)
|
data/lib/nobrainer.rb
CHANGED
@@ -13,7 +13,7 @@ module NoBrainer
|
|
13
13
|
|
14
14
|
# We eager load things that could be loaded when handling the first web request.
|
15
15
|
# Code that is loaded through the DSL of NoBrainer should not be eager loaded.
|
16
|
-
autoload :Document, :IndexManager, :Loader, :Fork, :Geo, :Lock
|
16
|
+
autoload :Document, :IndexManager, :Loader, :Fork, :Geo, :Lock, :Profiler
|
17
17
|
eager_autoload :Config, :Connection, :ConnectionManager, :Error,
|
18
18
|
:QueryRunner, :Criteria, :RQL
|
19
19
|
|
@@ -41,4 +41,5 @@ ActiveSupport.on_load(:i18n) do
|
|
41
41
|
I18n.load_path << File.dirname(__FILE__) + '/no_brainer/locale/en.yml'
|
42
42
|
end
|
43
43
|
|
44
|
+
require 'no_brainer/profiler/logger'
|
44
45
|
require 'no_brainer/railtie' if defined?(Rails)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nobrainer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.23.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas Viennot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rethinkdb
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.0.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.0.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,12 +171,16 @@ files:
|
|
171
171
|
- lib/no_brainer/loader.rb
|
172
172
|
- lib/no_brainer/locale/en.yml
|
173
173
|
- lib/no_brainer/lock.rb
|
174
|
+
- lib/no_brainer/logger.rb
|
175
|
+
- lib/no_brainer/profiler.rb
|
176
|
+
- lib/no_brainer/profiler/controller_runtime.rb
|
177
|
+
- lib/no_brainer/profiler/logger.rb
|
174
178
|
- lib/no_brainer/query_runner.rb
|
175
179
|
- lib/no_brainer/query_runner/connection_lock.rb
|
176
180
|
- lib/no_brainer/query_runner/database_on_demand.rb
|
177
181
|
- lib/no_brainer/query_runner/driver.rb
|
178
|
-
- lib/no_brainer/query_runner/logger.rb
|
179
182
|
- lib/no_brainer/query_runner/missing_index.rb
|
183
|
+
- lib/no_brainer/query_runner/profiler.rb
|
180
184
|
- lib/no_brainer/query_runner/reconnect.rb
|
181
185
|
- lib/no_brainer/query_runner/run_options.rb
|
182
186
|
- lib/no_brainer/query_runner/table_on_demand.rb
|
@@ -208,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
208
212
|
version: '0'
|
209
213
|
requirements: []
|
210
214
|
rubyforge_project:
|
211
|
-
rubygems_version: 2.4.
|
215
|
+
rubygems_version: 2.4.6
|
212
216
|
signing_key:
|
213
217
|
specification_version: 4
|
214
218
|
summary: ORM for RethinkDB
|