modis 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -0
- data/.ruby-version +1 -1
- data/.travis.yml +10 -5
- data/Gemfile +8 -4
- data/Gemfile.lock +42 -48
- data/README.md +2 -2
- data/benchmark/bench.rb +65 -0
- data/benchmark/find.rb +62 -0
- data/benchmark/persistence.rb +82 -0
- data/benchmark/redis/connection/fakedis.rb +90 -0
- data/lib/modis.rb +2 -1
- data/lib/modis/attribute.rb +47 -27
- data/lib/modis/configuration.rb +5 -3
- data/lib/modis/finder.rb +31 -19
- data/lib/modis/index.rb +19 -27
- data/lib/modis/model.rb +2 -3
- data/lib/modis/persistence.rb +87 -56
- data/lib/modis/version.rb +1 -1
- data/lib/tasks/quality.rake +19 -12
- data/modis.gemspec +12 -4
- data/spec/attribute_spec.rb +5 -5
- data/spec/finder_spec.rb +27 -1
- data/spec/persistence_spec.rb +57 -4
- data/spec/spec_helper.rb +8 -6
- data/spec/support/simplecov_helper.rb +9 -5
- metadata +35 -4
- data/.coveralls.yml +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6f800df4e32942fff0bab6bcc91be7c5703ad85
|
4
|
+
data.tar.gz: 44fb61a6e24d183599bc9b55372f327140696b30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb1be4a74d4b4b7c0ea6686b6fcba3acf1013b601ca580e993aeef84532e364e167e13e08475a6b820818f8f05cdada5eacd2f10ffb6af517920c57c731bd3f8
|
7
|
+
data.tar.gz: 6122913d3e5c734f0f7aa8cd1d2a52a1bdb5fbedcdcbd89c3ce7f3f74d35a255f20cf090512732dcc73c70c6f2116bfdfbed8964e8d6966f012f02411dba4923
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
AllCops:
|
2
2
|
Exclude:
|
3
3
|
- modis.gemspec
|
4
|
+
- vendor/**/*
|
4
5
|
|
5
6
|
LineLength:
|
6
7
|
Enabled: false
|
@@ -22,3 +23,9 @@ CyclomaticComplexity:
|
|
22
23
|
|
23
24
|
Style/SignalException:
|
24
25
|
EnforcedStyle: only_raise
|
26
|
+
|
27
|
+
Style/NumericLiterals:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Metrics/AbcSize:
|
31
|
+
Max: 25
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.2.0
|
data/.travis.yml
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
sudo: false
|
1
2
|
services:
|
2
|
-
|
3
|
+
- redis-server
|
3
4
|
language: ruby
|
4
5
|
rvm:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
- 2.0.0
|
7
|
+
- 2.1.5
|
8
|
+
- 2.2.0
|
9
|
+
- jruby-1.7.18
|
10
|
+
- rbx-2.4.1
|
11
|
+
env:
|
12
|
+
global:
|
13
|
+
secure: LrTz0Pq2ibNZuKDhdzcrvEUSNxUpPopEq9aJeCxy3UpV0v4vpHBtWV0S6zofvf98g/RkZ6cGI1u+0H578dHgE6pWTo+iR8LAwqPKofrFIWRkeo+M77Vs5swahb3mQyPOcig1hfVWDm25MsojePYm70eBIcBU55NWImtdePXfiU0=
|
data/Gemfile
CHANGED
@@ -2,12 +2,16 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gem 'rake'
|
4
4
|
gem 'rspec'
|
5
|
-
gem 'simplecov'
|
6
|
-
gem 'coveralls'
|
7
5
|
|
8
|
-
platform :
|
6
|
+
platform :mri do
|
7
|
+
gem 'codeclimate-test-reporter', require: nil
|
9
8
|
gem 'cane'
|
10
|
-
gem 'rubocop'
|
9
|
+
gem 'rubocop', require: false
|
10
|
+
gem 'simplecov', require: false
|
11
|
+
end
|
12
|
+
|
13
|
+
platform :mri_21 do
|
14
|
+
gem 'stackprof'
|
11
15
|
end
|
12
16
|
|
13
17
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,83 +1,76 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
modis (1.
|
4
|
+
modis (1.4.0)
|
5
5
|
activemodel (>= 3.0)
|
6
6
|
activesupport (>= 3.0)
|
7
7
|
connection_pool (>= 2)
|
8
|
+
hiredis (>= 0.5)
|
9
|
+
msgpack (>= 0.5)
|
8
10
|
redis (>= 3.0)
|
9
11
|
|
10
12
|
GEM
|
11
13
|
remote: https://rubygems.org/
|
12
14
|
specs:
|
13
|
-
activemodel (4.
|
14
|
-
activesupport (= 4.
|
15
|
+
activemodel (4.2.0)
|
16
|
+
activesupport (= 4.2.0)
|
15
17
|
builder (~> 3.1)
|
16
|
-
activesupport (4.
|
17
|
-
i18n (~> 0.
|
18
|
+
activesupport (4.2.0)
|
19
|
+
i18n (~> 0.7)
|
18
20
|
json (~> 1.7, >= 1.7.7)
|
19
21
|
minitest (~> 5.1)
|
20
|
-
thread_safe (~> 0.
|
22
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
21
23
|
tzinfo (~> 1.1)
|
22
24
|
ast (2.0.0)
|
25
|
+
astrolabe (1.3.0)
|
26
|
+
parser (>= 2.2.0.pre.3, < 3.0)
|
23
27
|
builder (3.2.2)
|
24
28
|
cane (2.6.2)
|
25
29
|
parallel
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
rest-client
|
30
|
-
simplecov (>= 0.7)
|
31
|
-
term-ansicolor
|
32
|
-
thor
|
30
|
+
codeclimate-test-reporter (0.4.5)
|
31
|
+
simplecov (>= 0.7.1, < 1.0.0)
|
32
|
+
connection_pool (2.1.0)
|
33
33
|
diff-lcs (1.2.5)
|
34
34
|
docile (1.1.5)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
minitest (5.
|
35
|
+
hiredis (0.5.2)
|
36
|
+
i18n (0.7.0)
|
37
|
+
json (1.8.2)
|
38
|
+
minitest (5.5.1)
|
39
|
+
msgpack (0.5.10)
|
39
40
|
multi_json (1.10.1)
|
40
|
-
|
41
|
-
|
42
|
-
parser (2.2.0.pre.4)
|
41
|
+
parallel (1.3.3)
|
42
|
+
parser (2.2.0.2)
|
43
43
|
ast (>= 1.1, < 3.0)
|
44
|
-
slop (~> 3.4, >= 3.4.5)
|
45
44
|
powerpack (0.0.9)
|
46
45
|
rainbow (2.0.0)
|
47
|
-
rake (10.
|
48
|
-
redis (3.
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
rspec-
|
55
|
-
|
56
|
-
rspec-core (3.0.4)
|
57
|
-
rspec-support (~> 3.0.0)
|
58
|
-
rspec-expectations (3.0.4)
|
46
|
+
rake (10.4.2)
|
47
|
+
redis (3.2.0)
|
48
|
+
rspec (3.1.0)
|
49
|
+
rspec-core (~> 3.1.0)
|
50
|
+
rspec-expectations (~> 3.1.0)
|
51
|
+
rspec-mocks (~> 3.1.0)
|
52
|
+
rspec-core (3.1.7)
|
53
|
+
rspec-support (~> 3.1.0)
|
54
|
+
rspec-expectations (3.1.2)
|
59
55
|
diff-lcs (>= 1.2.0, < 2.0)
|
60
|
-
rspec-support (~> 3.
|
61
|
-
rspec-mocks (3.
|
62
|
-
rspec-support (~> 3.
|
63
|
-
rspec-support (3.
|
64
|
-
rubocop (0.
|
65
|
-
|
56
|
+
rspec-support (~> 3.1.0)
|
57
|
+
rspec-mocks (3.1.3)
|
58
|
+
rspec-support (~> 3.1.0)
|
59
|
+
rspec-support (3.1.2)
|
60
|
+
rubocop (0.28.0)
|
61
|
+
astrolabe (~> 1.3)
|
62
|
+
parser (>= 2.2.0.pre.7, < 3.0)
|
66
63
|
powerpack (~> 0.0.6)
|
67
64
|
rainbow (>= 1.99.1, < 3.0)
|
68
65
|
ruby-progressbar (~> 1.4)
|
69
|
-
ruby-progressbar (1.
|
70
|
-
simplecov (0.9.
|
66
|
+
ruby-progressbar (1.7.1)
|
67
|
+
simplecov (0.9.1)
|
71
68
|
docile (~> 1.1.0)
|
72
|
-
multi_json
|
69
|
+
multi_json (~> 1.0)
|
73
70
|
simplecov-html (~> 0.8.0)
|
74
71
|
simplecov-html (0.8.0)
|
75
|
-
|
76
|
-
term-ansicolor (1.3.0)
|
77
|
-
tins (~> 1.0)
|
78
|
-
thor (0.19.1)
|
72
|
+
stackprof (0.2.7)
|
79
73
|
thread_safe (0.3.4)
|
80
|
-
tins (1.3.2)
|
81
74
|
tzinfo (1.2.2)
|
82
75
|
thread_safe (~> 0.1)
|
83
76
|
|
@@ -87,9 +80,10 @@ PLATFORMS
|
|
87
80
|
|
88
81
|
DEPENDENCIES
|
89
82
|
cane
|
90
|
-
|
83
|
+
codeclimate-test-reporter
|
91
84
|
modis!
|
92
85
|
rake
|
93
86
|
rspec
|
94
87
|
rubocop
|
95
88
|
simplecov
|
89
|
+
stackprof
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
[![Build Status](https://secure.travis-ci.org/ileitch/modis.png?branch=master)](http://travis-ci.org/ileitch/modis)
|
2
|
-
[![Code Climate](https://codeclimate.com/github/ileitch/modis.
|
3
|
-
[![Coverage
|
2
|
+
[![Code Climate](https://codeclimate.com/github/ileitch/modis/badges/gpa.svg)](https://codeclimate.com/github/ileitch/modis)
|
3
|
+
[![Test Coverage](https://codeclimate.com/github/ileitch/modis/badges/coverage.svg)](https://codeclimate.com/github/ileitch/modis)
|
4
4
|
|
5
5
|
# Modis
|
6
6
|
|
data/benchmark/bench.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'stackprof'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift('.')
|
5
|
+
require 'lib/modis'
|
6
|
+
|
7
|
+
puts "Profiler enabled." if ENV['PROFILE']
|
8
|
+
|
9
|
+
Modis.configure do |config|
|
10
|
+
config.namespace = 'modis_benchmark'
|
11
|
+
end
|
12
|
+
|
13
|
+
class Bench
|
14
|
+
def self.run
|
15
|
+
bench = new
|
16
|
+
yield(bench)
|
17
|
+
bench._run
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@bms = []
|
22
|
+
@profiles = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def report(name, &blk)
|
26
|
+
@bms << [name, blk]
|
27
|
+
end
|
28
|
+
|
29
|
+
def _run
|
30
|
+
Benchmark.bmbm do |x|
|
31
|
+
@bms.each do |name, blk|
|
32
|
+
x.report(name) do
|
33
|
+
with_profile(name, &blk)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
after
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def with_profile(name, &blk)
|
44
|
+
if ENV['PROFILE']
|
45
|
+
mode = :wall
|
46
|
+
out = "tmp/stackprof-#{mode}-#{name}.dump"
|
47
|
+
@profiles << out
|
48
|
+
StackProf.run(mode: mode, out: out, &blk)
|
49
|
+
else
|
50
|
+
blk.call
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def after
|
55
|
+
Modis.with_connection do |connection|
|
56
|
+
keys = connection.keys "#{Modis.config.namespace}:*"
|
57
|
+
connection.del(*keys) unless keys.empty?
|
58
|
+
end
|
59
|
+
|
60
|
+
return unless @profiles.any?
|
61
|
+
|
62
|
+
puts "\nProfiler dumps:"
|
63
|
+
@profiles.uniq.each { |dump| puts " * stackprof #{dump} --text" }
|
64
|
+
end
|
65
|
+
end
|
data/benchmark/find.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
$LOAD_PATH.unshift('benchmark')
|
2
|
+
require 'bench'
|
3
|
+
|
4
|
+
require 'redis/connection/fakedis'
|
5
|
+
# Redis::Connection::Fakedis.start_recording
|
6
|
+
Redis::Connection::Fakedis.start_replay(:find)
|
7
|
+
Modis.redis_options = { driver: :fakedis }
|
8
|
+
|
9
|
+
class User
|
10
|
+
include Modis::Model
|
11
|
+
|
12
|
+
attribute :name, :string
|
13
|
+
attribute :age, :integer
|
14
|
+
attribute :percentage, :float
|
15
|
+
attribute :created_at, :timestamp
|
16
|
+
attribute :flag, :boolean
|
17
|
+
attribute :array, :array
|
18
|
+
attribute :hash, :hash
|
19
|
+
attribute :string_or_hash, [:string, :hash]
|
20
|
+
|
21
|
+
index :name
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_user
|
25
|
+
User.create!(name: 'Test', age: 30, percentage: 50.0, created_at: Time.now,
|
26
|
+
flag: true, array: [1, 2, 3], hash: { k: :v }, string_or_hash: "an string")
|
27
|
+
end
|
28
|
+
|
29
|
+
user = create_user
|
30
|
+
|
31
|
+
n = 10_000
|
32
|
+
|
33
|
+
Bench.run do |b|
|
34
|
+
b.report(:find) do
|
35
|
+
n.times do
|
36
|
+
User.find(user.id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
b.report(:where) do
|
41
|
+
n.times do
|
42
|
+
User.where(name: user.name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
n = 1_000
|
48
|
+
i = 20
|
49
|
+
STDOUT.write "\n* Creating #{i} users for :where_multiple... "
|
50
|
+
STDOUT.flush
|
51
|
+
i.times { create_user }
|
52
|
+
puts "✔\n\n"
|
53
|
+
|
54
|
+
Bench.run do |b|
|
55
|
+
b.report(:where_multiple) do
|
56
|
+
n.times do
|
57
|
+
User.where(name: 'Test')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Redis::Connection::Fakedis.stop_recording(:find)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
$LOAD_PATH.unshift('benchmark')
|
2
|
+
require 'bench'
|
3
|
+
|
4
|
+
require 'redis/connection/fakedis'
|
5
|
+
# Redis::Connection::Fakedis.start_recording
|
6
|
+
Redis::Connection::Fakedis.start_replay(:persistence)
|
7
|
+
Modis.redis_options = { driver: :fakedis }
|
8
|
+
|
9
|
+
class User
|
10
|
+
include Modis::Model
|
11
|
+
|
12
|
+
attribute :name, :string, default: 'Test'
|
13
|
+
attribute :age, :integer
|
14
|
+
attribute :percentage, :float
|
15
|
+
attribute :created_at, :timestamp
|
16
|
+
attribute :flag, :boolean
|
17
|
+
attribute :array, :array
|
18
|
+
attribute :hash, :hash
|
19
|
+
attribute :string_or_hash, [:string, :hash]
|
20
|
+
|
21
|
+
index :name
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_user
|
25
|
+
User.create!(name: 'Test', age: 30, percentage: 50.0, created_at: Time.now,
|
26
|
+
flag: true, array: [1, 2, 3], hash: { k: :v }, string_or_hash: "an string")
|
27
|
+
end
|
28
|
+
|
29
|
+
n = 10_000
|
30
|
+
|
31
|
+
Bench.run do |b|
|
32
|
+
b.report(:create) do
|
33
|
+
n.times do
|
34
|
+
create_user
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
b.report(:save) do
|
39
|
+
n.times do
|
40
|
+
user = User.new
|
41
|
+
user.name = 'Test'
|
42
|
+
user.age = 30
|
43
|
+
user.percentage = 50.0
|
44
|
+
user.created_at = Time.now
|
45
|
+
user.flag = true
|
46
|
+
user.array = [1, 2, 3]
|
47
|
+
user.hash = { k: :v }
|
48
|
+
user.string_or_hash = "an string"
|
49
|
+
user.save!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
b.report(:initialize) do
|
54
|
+
n.times do
|
55
|
+
User.new(name: 'Test', age: 30, percentage: 50.0, created_at: Time.now,
|
56
|
+
flag: true, array: [1, 2, 3], hash: { k: :v }, string_or_hash: "an string")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
b.report(:update_without_changes) do
|
61
|
+
user = create_user
|
62
|
+
n.times do
|
63
|
+
user.update_attributes!(name: user.name, age: user.age)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
b.report(:update_with_changes) do
|
68
|
+
user = create_user
|
69
|
+
n.times do |i|
|
70
|
+
user.update_attribute(:name, i.to_s)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
b.report(:reload) do
|
75
|
+
user = create_user
|
76
|
+
n.times do
|
77
|
+
user.reload
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Redis::Connection::Fakedis.stop_recording(:persistence)
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# rubocop:disable all
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'redis/connection/hiredis'
|
5
|
+
|
6
|
+
class Redis
|
7
|
+
module Connection
|
8
|
+
class Fakedis < ::Redis::Connection::Hiredis
|
9
|
+
class << self
|
10
|
+
attr_accessor :reads, :read_indicies, :replaying, :recording
|
11
|
+
alias_method :replaying?, :replaying
|
12
|
+
alias_method :recording?, :recording
|
13
|
+
end
|
14
|
+
|
15
|
+
@reads = []
|
16
|
+
@read_indicies = []
|
17
|
+
|
18
|
+
def self.start_replay(name)
|
19
|
+
puts "Fakedis replaying."
|
20
|
+
self.replaying = true
|
21
|
+
|
22
|
+
@reads = Marshal.load(File.read(reads_path(name)))
|
23
|
+
@read_indicies = Marshal.load(File.read(read_indicies_path(name)))
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.start_recording
|
27
|
+
puts "Fakedis recording."
|
28
|
+
self.recording = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.stop_recording(name)
|
32
|
+
self.recording = false
|
33
|
+
|
34
|
+
puts "\nFakedis:"
|
35
|
+
puts " * #{reads.size} unique reads recorded"
|
36
|
+
|
37
|
+
FileUtils.mkdir_p("tmp/fakedis")
|
38
|
+
|
39
|
+
File.open(reads_path(name), 'w') { |fd| fd.write(Marshal.dump(reads)) }
|
40
|
+
File.open(read_indicies_path(name), 'w') { |fd| fd.write(Marshal.dump(read_indicies)) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.reads_path(name)
|
44
|
+
"tmp/fakedis/#{name}_reads.dump"
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.read_indicies_path(name)
|
48
|
+
"tmp/fakedis/#{name}_read_indicies.dump"
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(*args)
|
52
|
+
super
|
53
|
+
@reads_idx = -1
|
54
|
+
@read_depth = 0
|
55
|
+
end
|
56
|
+
|
57
|
+
def read
|
58
|
+
if self.class.recording?
|
59
|
+
@read_depth += 1
|
60
|
+
v = super
|
61
|
+
@read_depth -= 1
|
62
|
+
return v if @read_depth > 0
|
63
|
+
i = self.class.reads.index(v)
|
64
|
+
|
65
|
+
if i
|
66
|
+
self.class.read_indicies << i
|
67
|
+
else
|
68
|
+
self.class.reads << v
|
69
|
+
self.class.read_indicies << self.class.reads.size - 1
|
70
|
+
end
|
71
|
+
|
72
|
+
v
|
73
|
+
elsif self.class.replaying?
|
74
|
+
@reads_idx += 1
|
75
|
+
self.class.reads[self.class.read_indicies[@reads_idx]]
|
76
|
+
else
|
77
|
+
super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def write(v)
|
82
|
+
if self.class.replaying?
|
83
|
+
# Do nothing.
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|