pcbr 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/lib/pcbr.rb +16 -31
- data/pcbr.gemspec +11 -12
- metadata +16 -46
- data/.rspec +0 -1
- data/Gemfile +0 -3
- data/README.md +0 -29
- data/Rakefile +0 -8
- data/spec/_spec.rb +0 -172
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 479e8f9785c73a1569d807a1f311599f1285df24
|
4
|
+
data.tar.gz: 59569e2a2ac7eeeed617655e351fd3ea07743908
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 280c5a469bb446ec87f1fbc47e47cf77f4325e9c1162b6d4836c79f370d472dc99c71169fd0c58cecffbcf302cc583c8605dc163088b383f19b826bd0c33b62e
|
7
|
+
data.tar.gz: 5a8b362448c8d3276ea54257ead0c2fbdd8337c0ae3e1a48e5bc78acae17002f479ba63db68d025749bdad4f51c402f3401e71dfdc5bb74617be724b61f100cb
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 Victor Maslov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/lib/pcbr.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
|
-
require "deep_dup"
|
2
|
-
|
3
1
|
module PCBR
|
4
|
-
VERSION = "0.3.0"
|
5
|
-
|
6
2
|
class Error < RuntimeError
|
7
3
|
# def initialize body
|
8
4
|
# super "#{Module.nesting[1]} error: #{body}"
|
@@ -13,37 +9,35 @@ module PCBR
|
|
13
9
|
Storage.new &block
|
14
10
|
end
|
15
11
|
|
16
|
-
ARRAY_101 = [0, 0, 0]
|
17
12
|
class Storage
|
18
13
|
attr_reader :table
|
14
|
+
attr_reader :set
|
15
|
+
@@default_lambda = lambda do |a_, b_|
|
16
|
+
raise Error.new "comparison vectors are of the different length" unless a_.size == b_.size
|
17
|
+
tt = [0, 0, 0]
|
18
|
+
[*a_].zip([*b_]) do |a, b|
|
19
|
+
t = a <=> b and tt[t] = t
|
20
|
+
end
|
21
|
+
tt[0] + tt[1] + tt[2]
|
22
|
+
end
|
19
23
|
|
20
24
|
def initialize &block
|
25
|
+
require "set"
|
26
|
+
@set = ::Set.new
|
21
27
|
@table = []
|
22
|
-
@callback = block ||
|
23
|
-
ARRAY_101.dup.tap do |array|
|
24
|
-
[*a_].zip([*b_]) do |a, b|
|
25
|
-
t = a <=> b and array[t] = t
|
26
|
-
end
|
27
|
-
end.inject :+
|
28
|
-
}
|
28
|
+
@callback = block || @@default_lambda
|
29
29
|
end
|
30
30
|
|
31
31
|
def store key, vector = nil
|
32
|
-
raise Error.new "duplicating key" if @
|
33
|
-
|
34
|
-
vector = if vector
|
35
|
-
DeepDup.deep_dup vector
|
36
|
-
else
|
37
|
-
Array key
|
38
|
-
end
|
32
|
+
raise Error.new "duplicating key" if @set.include? key
|
33
|
+
vector = Array key if vector.nil?
|
39
34
|
score = 0
|
40
35
|
@table.each do |item|
|
41
|
-
# TODO test of this exception
|
42
|
-
raise Error.new "comparison vectors are of the different length" unless vector.size == item[1].size
|
43
36
|
point = @callback.call vector, item[1]
|
44
|
-
score += point
|
45
37
|
item[2] -= point
|
38
|
+
score += point
|
46
39
|
end
|
40
|
+
@set.add key
|
47
41
|
@table.push [key, vector, score]
|
48
42
|
end
|
49
43
|
|
@@ -56,14 +50,5 @@ module PCBR
|
|
56
50
|
@table.sort_by.with_index{ |item, i| [-item[2], i] }.map(&:first)
|
57
51
|
end
|
58
52
|
|
59
|
-
# def quality
|
60
|
-
# factorial = ->x{ (1..x).inject(:*) }
|
61
|
-
# (2...@table.size).each do |sublength|
|
62
|
-
# combinations = factorial[@table.size] / factorial[sublength] / factorial[@table.size - sublength]
|
63
|
-
# comparisons = sublength * (sublength - 1) / 2
|
64
|
-
# p [sublength, combinations, comparisons, combinations * comparisons]
|
65
|
-
# end
|
66
|
-
# end
|
67
|
-
|
68
53
|
end
|
69
54
|
end
|
data/pcbr.gemspec
CHANGED
@@ -1,20 +1,19 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "pcbr"
|
3
|
-
spec.version =
|
3
|
+
spec.version = "0.5.0"
|
4
|
+
spec.summary = "Pair Comparison Based Rating"
|
5
|
+
|
4
6
|
spec.author = "Victor Maslov"
|
5
7
|
spec.email = "nakilon@gmail.com"
|
6
|
-
spec.summary = "Pair Comparison Based Rating"
|
7
|
-
spec.description = "Making ratings is fun. After applying my method several times I've decided to gemify it."
|
8
|
-
spec.homepage = "https://github.com/Nakilon/pcbr"
|
9
8
|
spec.license = "MIT"
|
9
|
+
spec.metadata = {"source_code_uri" => "https://github.com/nakilon/pcbr"}
|
10
|
+
spec.description = <<-EOF
|
11
|
+
Making ratings is fun. After applying my method several times I've decided to gemify it.
|
12
|
+
This is one of the first gems I made so it's far for being nicely done.
|
13
|
+
EOF
|
10
14
|
|
11
|
-
spec.
|
12
|
-
spec.
|
13
|
-
|
14
|
-
spec.add_dependency "deep_dup"
|
15
|
-
|
16
|
-
spec.add_development_dependency "bundler"
|
17
|
-
spec.add_development_dependency "rspec", "~> 3.3.0"
|
15
|
+
spec.required_ruby_version = ">=2"
|
16
|
+
spec.add_development_dependency "minitest"
|
18
17
|
|
19
|
-
spec.
|
18
|
+
spec.files = %w{ LICENSE pcbr.gemspec lib/pcbr.rb }
|
20
19
|
end
|
metadata
CHANGED
@@ -1,92 +1,62 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pcbr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Maslov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: minitest
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - '>='
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: bundler
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '>='
|
17
|
+
- - ">="
|
32
18
|
- !ruby/object:Gem::Version
|
33
19
|
version: '0'
|
34
20
|
type: :development
|
35
21
|
prerelease: false
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
|
-
- -
|
24
|
+
- - ">="
|
39
25
|
- !ruby/object:Gem::Version
|
40
26
|
version: '0'
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
requirements:
|
45
|
-
- - ~>
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 3.3.0
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ~>
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 3.3.0
|
55
|
-
description: Making ratings is fun. After applying my method several times I've decided
|
56
|
-
to gemify it.
|
27
|
+
description: |2
|
28
|
+
Making ratings is fun. After applying my method several times I've decided to gemify it.
|
29
|
+
This is one of the first gems I made so it's far for being nicely done.
|
57
30
|
email: nakilon@gmail.com
|
58
31
|
executables: []
|
59
32
|
extensions: []
|
60
33
|
extra_rdoc_files: []
|
61
34
|
files:
|
62
|
-
-
|
63
|
-
- Gemfile
|
64
|
-
- README.md
|
65
|
-
- Rakefile
|
35
|
+
- LICENSE
|
66
36
|
- lib/pcbr.rb
|
67
37
|
- pcbr.gemspec
|
68
|
-
|
69
|
-
homepage: https://github.com/Nakilon/pcbr
|
38
|
+
homepage:
|
70
39
|
licenses:
|
71
40
|
- MIT
|
72
|
-
metadata:
|
41
|
+
metadata:
|
42
|
+
source_code_uri: https://github.com/nakilon/pcbr
|
73
43
|
post_install_message:
|
74
44
|
rdoc_options: []
|
75
45
|
require_paths:
|
76
46
|
- lib
|
77
47
|
required_ruby_version: !ruby/object:Gem::Requirement
|
78
48
|
requirements:
|
79
|
-
- -
|
49
|
+
- - ">="
|
80
50
|
- !ruby/object:Gem::Version
|
81
|
-
version: 2
|
51
|
+
version: '2'
|
82
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
53
|
requirements:
|
84
|
-
- -
|
54
|
+
- - ">="
|
85
55
|
- !ruby/object:Gem::Version
|
86
56
|
version: '0'
|
87
57
|
requirements: []
|
88
58
|
rubyforge_project:
|
89
|
-
rubygems_version: 2.
|
59
|
+
rubygems_version: 2.5.2.3
|
90
60
|
signing_key:
|
91
61
|
specification_version: 4
|
92
62
|
summary: Pair Comparison Based Rating
|
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--color
|
data/Gemfile
DELETED
data/README.md
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
# PCBR (Pairs Comparison Based Rating)
|
2
|
-
|
3
|
-
Making ratings is fun. After applying my method several times I've decided to gemify it.
|
4
|
-
|
5
|
-
### Examples
|
6
|
-
|
7
|
-
See [`describe "examples" do` in specs](spec/_spec.rb).
|
8
|
-
|
9
|
-
### How it works
|
10
|
-
|
11
|
-
The first idea of rating items by one-to-one comparison was about QuakeLive players in 2013 or so and it didn't work well. At that time I was thinking about tree data structure. Later in May 2015 I've realised that it's really about dots in n-dimensional space and sectors. Applying it to Reddit RSS made my feed 50% more interesting.
|
12
|
-
|
13
|
-
TODO: describe/illustrate algorithm?
|
14
|
-
|
15
|
-
~~At the moment it's a "proof of concept" -- it needs huge optimisations for lookups, maybe using trees.~~
|
16
|
-
|
17
|
-
It worked fine in production for a project with huge computations where you can't find the best solution but have to find anything good in adequate time. Traversing the tree using this with a vector of `[leaf's quality, depth]` made things better than depth-first search with lots of ueristics.
|
18
|
-
|
19
|
-
### Installation
|
20
|
-
|
21
|
-
$ gem install pcbr
|
22
|
-
|
23
|
-
### Testing with RSpec before contributing
|
24
|
-
|
25
|
-
rspec
|
26
|
-
|
27
|
-
or
|
28
|
-
|
29
|
-
rake spec
|
data/Rakefile
DELETED
data/spec/_spec.rb
DELETED
@@ -1,172 +0,0 @@
|
|
1
|
-
require_relative "../lib/pcbr"
|
2
|
-
|
3
|
-
|
4
|
-
require "pp"
|
5
|
-
|
6
|
-
|
7
|
-
describe "basic specs" do
|
8
|
-
|
9
|
-
example "scalar key without vector and without &block" do
|
10
|
-
rating = PCBR.new
|
11
|
-
rating.store 1
|
12
|
-
rating.store 2
|
13
|
-
expect(rating.sorted).to eq([2, 1])
|
14
|
-
end
|
15
|
-
|
16
|
-
# example "#size" do
|
17
|
-
# rating = PCBR.new
|
18
|
-
# rating.store 1
|
19
|
-
# rating.store 2
|
20
|
-
# expect(rating.size).to eq(2)
|
21
|
-
# end
|
22
|
-
|
23
|
-
example "Nil elements in vector are ignored" do
|
24
|
-
rating = PCBR.new
|
25
|
-
rating.store 1, [1, nil]
|
26
|
-
rating.store 2, [2, nil]
|
27
|
-
rating.store 3, [nil, 3]
|
28
|
-
rating.store 4, [nil, 4]
|
29
|
-
expect(rating.sorted).to eq([2, 4, 1, 3])
|
30
|
-
end
|
31
|
-
|
32
|
-
example "&block" do
|
33
|
-
n = 0
|
34
|
-
rating = PCBR.new do |a, b|
|
35
|
-
n += 1
|
36
|
-
a <=> b
|
37
|
-
end
|
38
|
-
rating.store 1
|
39
|
-
rating.store 2
|
40
|
-
rating.store 3
|
41
|
-
rating.store 4
|
42
|
-
expect(rating.sorted).to eq([4, 3, 2, 1])
|
43
|
-
expect(n).to eq(6)
|
44
|
-
end
|
45
|
-
|
46
|
-
example "#sorted and #score[key]" do
|
47
|
-
rating = PCBR.new
|
48
|
-
table = [
|
49
|
-
[1, [1, 1], -1],
|
50
|
-
[2, [2, 2], 5],
|
51
|
-
[3, [0, 0], -5],
|
52
|
-
[4, [1, 2], 3],
|
53
|
-
[6, [1, 1], -1],
|
54
|
-
[5, [0, 2], -1],
|
55
|
-
].each do |key, vector, |
|
56
|
-
rating.store key, vector
|
57
|
-
end
|
58
|
-
expect(rating.sorted).to eq([2, 4, 1, 6, 5, 3])
|
59
|
-
expect(rating.table.map{ |i| i[2] }.inject(:+)).to be_zero
|
60
|
-
table.each do |key, _, score|
|
61
|
-
expect(rating.score(key)).to eq(score)
|
62
|
-
end
|
63
|
-
expect(rating.table).to eq(table)
|
64
|
-
end
|
65
|
-
|
66
|
-
# example "quality estimation" do
|
67
|
-
# rating = PCBR.new
|
68
|
-
# table = [
|
69
|
-
# [1, [1, 1]],
|
70
|
-
# [2, [2, 2]],
|
71
|
-
# [3, [0, 0]],
|
72
|
-
# [4, [1, 2]],
|
73
|
-
# [6, [1, 1]],
|
74
|
-
# [5, [0, 2]],
|
75
|
-
# ].each do |key, vector, |
|
76
|
-
# rating.store key, vector
|
77
|
-
# end
|
78
|
-
# end
|
79
|
-
|
80
|
-
example "duplicating keys are forbidden" do
|
81
|
-
rating = PCBR.new
|
82
|
-
rating.store 0
|
83
|
-
expect{ rating.store 0 }.to raise_error PCBR::Error
|
84
|
-
end
|
85
|
-
|
86
|
-
example "keys and vectors are dupped" do
|
87
|
-
rating = PCBR.new
|
88
|
-
a = [[1]]
|
89
|
-
v = [0]
|
90
|
-
rating.store a, v
|
91
|
-
a[0][0] = 2
|
92
|
-
rating.store [[2]], [1] # expect no PCBR::Error
|
93
|
-
v[0] = 3
|
94
|
-
rating.store [[3]], [2]
|
95
|
-
expect(rating.sorted).to eq [[[3]], [[2]], [[1]]]
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
|
101
|
-
describe "examples" do
|
102
|
-
|
103
|
-
example "github repos" do
|
104
|
-
repos = {
|
105
|
-
# Image Processing Library
|
106
|
-
"IPL: ImageMagick/ImageMagick" => {issue: 36, pr: 0, watch: 29, star: 375, fork: 89},
|
107
|
-
"IPL: jcupitt/libvips" => {issue: 32, pr: 1, watch: 43, star: 753, fork: 72},
|
108
|
-
# Packet Manager
|
109
|
-
"PM: Homebrew/brew" => {issue: 14, pr: 13, watch: 61, star: 1207, fork: 345},
|
110
|
-
"PM: Linuxbrew/brew" => {issue: 21, pr: 2, watch: 5, star: 52, fork: 345},
|
111
|
-
# one gem depending on another one
|
112
|
-
"gem: dblock/slack-ruby-bot" => {issue: 15, pr: 0, watch: 13, star: 251, fork: 55},
|
113
|
-
"gem: dblock/slack-ruby-client" => {issue: 22, pr: 2, watch: 4, star: 206, fork: 37},
|
114
|
-
# Programming Language
|
115
|
-
"PL: crystal-lang/crystal" => {issue: 267, pr: 44, watch: 255, star: 4952, fork: 412},
|
116
|
-
"PL: elixir-lang/elixir" => {issue: 21, pr: 1, watch: 518, star: 7029, fork: 975},
|
117
|
-
"PL: golang/go" => {issue: 2293, pr: 1, watch: 1521, star: 17067, fork: 2147},
|
118
|
-
"PL: racket/racket" => {issue: 33, pr: 53, watch: 124, star: 1455, fork: 301},
|
119
|
-
"PL: rust-lang/rust" => {issue: 2411, pr: 119, watch: 1012, star: 16790, fork: 3200},
|
120
|
-
# Ruby Web Framework
|
121
|
-
"RWF: padrino/padrino-framework" => {issue: 44, pr: 2, watch: 137, star: 2782, fork: 454},
|
122
|
-
"RWF: sinatra/sinatra" => {issue: 12, pr: 11, watch: 377, star: 7892, fork: 1467},
|
123
|
-
# Ruby Version Manager
|
124
|
-
"RVM: rbenv/rbenv" => {issue: 24, pr: 12, watch: 301, star: 8257, fork: 769},
|
125
|
-
"RVM: rvm/rvm" => {issue: 160, pr: 5, watch: 154, star: 3328, fork: 793},
|
126
|
-
# DevOps Tool
|
127
|
-
"DOT: ansible/ansible" => {issue: 1074, pr: 322, watch: 1339, star: 16926, fork: 5075},
|
128
|
-
"DOT: chef/chef" => {issue: 422, pr: 52, watch: 387, star: 4265, fork: 1774},
|
129
|
-
"DOT: capistrano/capistrano" => {issue: 38, pr: 6, watch: 339, star: 8392, fork: 1365},
|
130
|
-
}
|
131
|
-
|
132
|
-
create_rating = lambda do |&callback|
|
133
|
-
PCBR.new.tap do |rating|
|
134
|
-
repos.each do |repo_name, repo_stats|
|
135
|
-
rating.store repo_name, callback[repo_stats, repo_name]
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
contribution_intensivity_rating = create_rating.call do |repo_stats| [
|
141
|
-
repo_stats[:pr],
|
142
|
-
-repo_stats[:fork],
|
143
|
-
] end
|
144
|
-
|
145
|
-
quality_rating = create_rating.call do |repo_stats| [
|
146
|
-
repo_stats[:star],
|
147
|
-
-repo_stats[:issue],
|
148
|
-
] end
|
149
|
-
|
150
|
-
resulting_rating = create_rating.call do |repo_stats, repo_name| [
|
151
|
-
contribution_intensivity_rating.score(repo_name),
|
152
|
-
quality_rating.score(repo_name),
|
153
|
-
] end
|
154
|
-
|
155
|
-
aggregate_failures do
|
156
|
-
expect(
|
157
|
-
resulting_rating.sorted.map(&:split).group_by(&:first).each do |category, group|
|
158
|
-
group.map! &:last
|
159
|
-
end.to_a
|
160
|
-
).to eq( [
|
161
|
-
["PM:", %w{ Homebrew/brew Linuxbrew/brew }],
|
162
|
-
["RVM:", %w{ rbenv/rbenv rvm/rvm }],
|
163
|
-
["PL:", %w{ racket/racket crystal-lang/crystal elixir-lang/elixir rust-lang/rust golang/go }],
|
164
|
-
["DOT:", %w{ ansible/ansible capistrano/capistrano chef/chef }],
|
165
|
-
["RWF:", %w{ sinatra/sinatra padrino/padrino-framework }],
|
166
|
-
["gem:", %w{ dblock/slack-ruby-bot dblock/slack-ruby-client }],
|
167
|
-
["IPL:", %w{ jcupitt/libvips ImageMagick/ImageMagick }],
|
168
|
-
] )
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
end
|