inci_score 3.0.3 → 3.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +4 -5
- data/config/catalog.yml +1 -0
- data/lib/inci_score/api.rb +1 -2
- data/lib/inci_score/cli.rb +2 -7
- data/lib/inci_score/computer.rb +3 -8
- data/lib/inci_score/ingredient.rb +3 -7
- data/lib/inci_score/recognizer.rb +7 -8
- data/lib/inci_score/recognizer_rules.rb +2 -2
- data/lib/inci_score/refinements.rb +0 -5
- data/lib/inci_score/version.rb +1 -1
- data/spec/integration/api_spec.rb +1 -1
- data/spec/stubs.rb +1 -1
- data/spec/unit/cli_spec.rb +1 -1
- data/spec/unit/ingredient_spec.rb +0 -6
- data/spec/unit/recognizer_spec.rb +6 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8aab0ebc926de421bb3aaecf7c52a8522c8f47e4
|
4
|
+
data.tar.gz: 1306f8fd4375384c4c2965155759cfe251b515fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ce833b953c31f2097356e87c2c33fbbe49e866e26e541b836b8bfba7b2b999ef7cd5ae3d3e81b92ad05e473aabdfec7fb0c45496f7cd3aa096103e3b9fac8a1
|
7
|
+
data.tar.gz: 046d1e9c4a481919546f27287442401ee05d9d2265cd1413eff5bcfb5f75b6de1619439bba3aaeef78b6fb6f8173a93ca70737a165d311c7614990242f46d88b
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -105,9 +105,8 @@ curl http://127.0.0.1:9292?src=aqua,dimethicone
|
|
105
105
|
### Getting help
|
106
106
|
You can get CLI interface help by:
|
107
107
|
```shell
|
108
|
-
Usage: inci_score --src="aqua, parfum, etc"
|
108
|
+
Usage: inci_score --src="aqua, parfum, etc"
|
109
109
|
-s, --src=SRC The INCI list: "aqua, parfum, etc"
|
110
|
-
-p, --precise Compute components more precisely (slower)
|
111
110
|
--http=PORT Start HTTP server on the specified port
|
112
111
|
-h, --help Prints this help
|
113
112
|
```
|
@@ -130,12 +129,12 @@ I registered these benchmarks with a MacBook PRO 15 mid 2015 having these specs:
|
|
130
129
|
As always i used [wrk](https://github.com/wg/wrk) as the loading tool.
|
131
130
|
I measured the library three times, picking the best lap.
|
132
131
|
```shell
|
133
|
-
wrk -t 4 -c 100 -d 30s --timeout 2000 "http://0.0.0.0:9292/?src=<source
|
132
|
+
wrk -t 4 -c 100 -d 30s --timeout 2000 "http://0.0.0.0:9292/?src=<source>"
|
134
133
|
```
|
135
134
|
|
136
135
|
### Results
|
137
136
|
| Source | Throughput (req/s) |
|
138
137
|
| --------------------------: | -----------------: |
|
139
|
-
| aqua,parfum,zeolite |
|
140
|
-
| agua,porfum,zeolithe |
|
138
|
+
| aqua,parfum,zeolite | 20296.75 |
|
139
|
+
| agua,porfum,zeolithe | 1098.45 |
|
141
140
|
| agua/water,porfum/fragrance | 1599.47 |
|
data/config/catalog.yml
CHANGED
data/lib/inci_score/api.rb
CHANGED
@@ -12,8 +12,7 @@ module InciScore
|
|
12
12
|
def call(env)
|
13
13
|
req = Rack::Request.new(env)
|
14
14
|
src = req.params["src"]
|
15
|
-
|
16
|
-
json = src ? Computer.new(src: src, catalog: catalog, precise: !!precise).call.to_json : %q({"error": "no valid source"})
|
15
|
+
json = src ? Computer.new(src: src, catalog: catalog).call.to_json : %q({"error": "no valid source"})
|
17
16
|
["200", {"Content-Type" => "application/json"}, [json]]
|
18
17
|
end
|
19
18
|
end
|
data/lib/inci_score/cli.rb
CHANGED
@@ -10,28 +10,23 @@ module InciScore
|
|
10
10
|
@catalog = catalog
|
11
11
|
@src = nil
|
12
12
|
@port = nil
|
13
|
-
@precise = nil
|
14
13
|
end
|
15
14
|
|
16
15
|
def call(server_klass: Server, computer_klass: Computer)
|
17
16
|
parser.parse!(@args)
|
18
17
|
return server_klass.new(port: @port, preload: true).run if @port
|
19
18
|
return @io.puts(%q{Specify inci list as: --src="aqua, parfum, etc"}) unless @src
|
20
|
-
@io.puts computer_klass.new(src: @src, catalog: @catalog
|
19
|
+
@io.puts computer_klass.new(src: @src, catalog: @catalog).call
|
21
20
|
end
|
22
21
|
|
23
22
|
private def parser
|
24
23
|
OptionParser.new do |opts|
|
25
|
-
opts.banner = %q{Usage: inci_score --src="aqua, parfum, etc"
|
24
|
+
opts.banner = %q{Usage: inci_score --src="aqua, parfum, etc"}
|
26
25
|
|
27
26
|
opts.on("-sSRC", "--src=SRC", %q{The INCI list: "aqua, parfum, etc"}) do |src|
|
28
27
|
@src = src
|
29
28
|
end
|
30
29
|
|
31
|
-
opts.on("-p", "--precise", "Compute components more precisely (slower)") do |precise|
|
32
|
-
@precise = precise
|
33
|
-
end
|
34
|
-
|
35
30
|
opts.on("--http=PORT", "Start HTTP server on the specified port") do |port|
|
36
31
|
@port = port
|
37
32
|
end
|
data/lib/inci_score/computer.rb
CHANGED
@@ -12,14 +12,12 @@ module InciScore
|
|
12
12
|
def initialize(src:,
|
13
13
|
catalog: Catalog.fetch,
|
14
14
|
tolerance: TOLERANCE,
|
15
|
-
rules: Normalizer::DEFAULT_RULES
|
16
|
-
precise: false)
|
15
|
+
rules: Normalizer::DEFAULT_RULES)
|
17
16
|
@src = src
|
18
17
|
@catalog = catalog
|
19
18
|
@tolerance = Float(tolerance)
|
20
19
|
@rules = rules
|
21
20
|
@unrecognized = []
|
22
|
-
@precise = precise
|
23
21
|
end
|
24
22
|
|
25
23
|
def call
|
@@ -34,15 +32,12 @@ module InciScore
|
|
34
32
|
end
|
35
33
|
|
36
34
|
private def ingredients
|
37
|
-
@ingredients ||=
|
38
|
-
tokens = Normalizer.new(src: @src, rules: @rules).call
|
39
|
-
Ingredient.bulk(tokens)
|
40
|
-
end
|
35
|
+
@ingredients ||= Normalizer.new(src: @src, rules: @rules).call
|
41
36
|
end
|
42
37
|
|
43
38
|
private def components
|
44
39
|
@components ||= ingredients.map do |ingredient|
|
45
|
-
Recognizer.new(ingredient, @catalog).call
|
40
|
+
Recognizer.new(ingredient, @catalog).call.tap do |component|
|
46
41
|
@unrecognized << ingredient unless component
|
47
42
|
end
|
48
43
|
end.compact
|
@@ -5,13 +5,9 @@ module InciScore
|
|
5
5
|
PARENTHESIS = %w[( ) [ ]]
|
6
6
|
DETAILS_RULE = /(\(.+\)|\[.+\])/
|
7
7
|
|
8
|
-
def self.bulk(tokens)
|
9
|
-
tokens.map { |raw| new(raw) }
|
10
|
-
end
|
11
|
-
|
12
8
|
def initialize(raw)
|
13
|
-
@raw = raw
|
14
|
-
@tokens = raw.split(SLASH_RULE).map(&:strip)
|
9
|
+
@raw = raw.to_s
|
10
|
+
@tokens = @raw.split(SLASH_RULE).map(&:strip)
|
15
11
|
end
|
16
12
|
|
17
13
|
def to_s
|
@@ -28,7 +24,7 @@ module InciScore
|
|
28
24
|
end
|
29
25
|
|
30
26
|
private def synonims
|
31
|
-
@tokens[1, @tokens.size]
|
27
|
+
@tokens[1, @tokens.size].to_a
|
32
28
|
end
|
33
29
|
|
34
30
|
private def details
|
@@ -8,30 +8,29 @@ module InciScore
|
|
8
8
|
|
9
9
|
attr_reader :applied
|
10
10
|
|
11
|
-
def initialize(ingredient, catalog, rules = DEFAULT_RULES)
|
12
|
-
@ingredient = ingredient
|
11
|
+
def initialize(ingredient, catalog, rules = DEFAULT_RULES, wrapper = Ingredient)
|
12
|
+
@ingredient = wrapper.new(ingredient)
|
13
13
|
@catalog = catalog
|
14
14
|
@rules = rules
|
15
15
|
@applied = []
|
16
16
|
end
|
17
17
|
|
18
|
-
def call
|
18
|
+
def call
|
19
19
|
return if @ingredient.to_s.empty?
|
20
|
-
component = find_component
|
20
|
+
component = find_component
|
21
21
|
return unless component
|
22
22
|
Component.new(component, @catalog[component])
|
23
23
|
end
|
24
24
|
|
25
|
-
private def find_component
|
25
|
+
private def find_component
|
26
26
|
@rules.reduce(nil) do |component, rule|
|
27
27
|
break(component) if component
|
28
28
|
applied << rule
|
29
|
-
apply(rule
|
29
|
+
apply(rule)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
private def apply(rule
|
34
|
-
return rule.call(@ingredient.to_s, @catalog) unless precise
|
33
|
+
private def apply(rule)
|
35
34
|
@ingredient.values.map do |value|
|
36
35
|
rule.call(value, @catalog)
|
37
36
|
end.find(&:itself)
|
@@ -58,14 +58,14 @@ module InciScore
|
|
58
58
|
def call(src, catalog)
|
59
59
|
tokens(src).each do |token|
|
60
60
|
catalog.each do |component, _|
|
61
|
-
return component if component.
|
61
|
+
return component if component.include?(token)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
nil
|
65
65
|
end
|
66
66
|
|
67
67
|
def tokens(src)
|
68
|
-
(src.split(" ") - UNMATCHABLE).reject { |t| t.size < TOLERANCE }.
|
68
|
+
(src.split(" ") - UNMATCHABLE).reject { |t| t.size < TOLERANCE }.sort! { |a, b| b.size <=> a.size }
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
data/lib/inci_score/version.rb
CHANGED
@@ -12,7 +12,7 @@ describe InciScore::Api do
|
|
12
12
|
status, score = Stubs.statuses[i], Stubs.scores[i]
|
13
13
|
|
14
14
|
it "cosmetic #{i} must get a proper response" do
|
15
|
-
get "/", src: src
|
15
|
+
get "/", src: src
|
16
16
|
assert last_response.ok?
|
17
17
|
last_response.content_type.must_equal "application/json"
|
18
18
|
body = JSON::parse(last_response.body)
|
data/spec/stubs.rb
CHANGED
data/spec/unit/cli_spec.rb
CHANGED
@@ -12,7 +12,7 @@ describe InciScore::CLI do
|
|
12
12
|
begin
|
13
13
|
InciScore::CLI.new(args: %w[--help], io: io, catalog: Stubs.catalog).call
|
14
14
|
rescue SystemExit
|
15
|
-
io.string.must_equal "Usage: inci_score --src=\"aqua, parfum, etc\"
|
15
|
+
io.string.must_equal "Usage: inci_score --src=\"aqua, parfum, etc\"\n -s, --src=SRC The INCI list: \"aqua, parfum, etc\"\n --http=PORT Start HTTP server on the specified port\n -h, --help Prints this help\n"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -1,12 +1,6 @@
|
|
1
1
|
require "helper"
|
2
2
|
|
3
3
|
describe InciScore::Ingredient do
|
4
|
-
it "must create instances in bulk" do
|
5
|
-
InciScore::Ingredient.bulk(Stubs.ingredients.first).each do |ingredient|
|
6
|
-
ingredient.must_be_instance_of InciScore::Ingredient
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
4
|
it "must be represented as a string" do
|
11
5
|
ingredient = InciScore::Ingredient.new("acrylamidopropyltrimonium chloride/acrylates copolymer")
|
12
6
|
ingredient.to_s.must_equal "acrylamidopropyltrimonium chloride/acrylates copolymer"
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require "helper"
|
2
|
-
require "inci_score/recognizer"
|
3
2
|
|
4
3
|
describe InciScore::Recognizer do
|
5
4
|
let(:rules) { [] }
|
@@ -22,6 +21,12 @@ describe InciScore::Recognizer do
|
|
22
21
|
recognizer.applied.must_equal InciScore::Recognizer::DEFAULT_RULES[0,1]
|
23
22
|
end
|
24
23
|
|
24
|
+
it "must recognize by key by using synonim" do
|
25
|
+
recognizer = InciScore::Recognizer.new("olio di oliva/olea europea", Stubs.catalog)
|
26
|
+
recognizer.call
|
27
|
+
recognizer.applied.must_equal InciScore::Recognizer::DEFAULT_RULES[0,1]
|
28
|
+
end
|
29
|
+
|
25
30
|
it "must recognize by key and levenshtein" do
|
26
31
|
recognizer = InciScore::Recognizer.new("agua", Stubs.catalog)
|
27
32
|
recognizer.call
|
@@ -39,11 +44,4 @@ describe InciScore::Recognizer do
|
|
39
44
|
recognizer.call
|
40
45
|
recognizer.applied.must_equal InciScore::Recognizer::DEFAULT_RULES
|
41
46
|
end
|
42
|
-
|
43
|
-
it "must recognize component precisely" do
|
44
|
-
ingredient = InciScore::Ingredient.new("olio di oliva/olea europea")
|
45
|
-
recognizer = InciScore::Recognizer.new(ingredient, Stubs.catalog)
|
46
|
-
recognizer.call(true)
|
47
|
-
recognizer.applied.must_equal InciScore::Recognizer::DEFAULT_RULES[0,1]
|
48
|
-
end
|
49
47
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inci_score
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- costajob
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: puma
|