jev-feels 0.1.0 → 0.2.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/README.md +57 -1
- data/lib/jev/registry.rb +15 -6
- data/lib/jev/version.rb +1 -1
- data/lib/jev-feels/string.rb +3 -0
- data/lib/jev.rb +45 -13
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 125dde58282251c7692d030e90352e098cf1785bc38904cf6021098d073d2f8a
|
|
4
|
+
data.tar.gz: 6bdf7fb784623b94cde049148294a1513e59207ccde0fd683869bbb4cc639a6d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b5a17cbde5d54178e39eed6600fdff431f5fdfa0515af09f79f4711eb19b67148a87e669a973755d2afa9546c2fcd5e6e14e15b29d1ddc4908834bc24ca4570
|
|
7
|
+
data.tar.gz: fb31b5c3f4fb3d90204cbfa815a5bf3aff537eb8611645f5099c79b775f1fd6d8f6427dc4ea603a8b7f670278aae61fe7b7e6e009e7136528fd75ab2149c0c82
|
data/README.md
CHANGED
|
@@ -25,6 +25,56 @@ if Jev.feels?(email, :urgent)
|
|
|
25
25
|
end
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## Ruby on Rails
|
|
29
|
+
|
|
30
|
+
Gemfile, initializer, then an ordinary condition. Bundler loads the gem — no extra `require` unless you want sugar on `String`.
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
# Gemfile
|
|
34
|
+
gem "jev-feels"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
# config/initializers/jev.rb
|
|
39
|
+
Jev.configure do |config|
|
|
40
|
+
config.api_key = ENV.fetch("JEV_API_KEY")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
Jev.define :urgent, "Requires immediate attention or action"
|
|
44
|
+
Jev.define SupportEmail, :urgent, "Outage, customers cannot sign in"
|
|
45
|
+
Jev.define Comment, :urgent, "Legal takedown or self-harm"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
class SupportEmail < ApplicationRecord
|
|
50
|
+
def urgent?
|
|
51
|
+
Jev.feels?(body, SupportEmail, :urgent)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
To use `#feels?` on strings across the app, require the String extension in the initializer:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
# config/initializers/jev.rb
|
|
60
|
+
require "jev-feels/string"
|
|
61
|
+
|
|
62
|
+
Jev.configure do |config|
|
|
63
|
+
config.api_key = ENV.fetch("JEV_API_KEY")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
Jev.define :urgent, "Requires immediate attention or action"
|
|
67
|
+
Jev.define SupportEmail, :urgent, "Outage, customers cannot sign in"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
class SupportEmail < ApplicationRecord
|
|
72
|
+
def urgent?
|
|
73
|
+
body.feels?(SupportEmail, :urgent)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
28
78
|
## String sugar
|
|
29
79
|
|
|
30
80
|
`require "feels"` does not change `String`. Opt in with a refinement:
|
|
@@ -39,6 +89,7 @@ Or, if you really want a global patch:
|
|
|
39
89
|
|
|
40
90
|
```ruby
|
|
41
91
|
require "feels/string"
|
|
92
|
+
# or: require "jev-feels/string"
|
|
42
93
|
|
|
43
94
|
email.feels?(:urgent)
|
|
44
95
|
```
|
|
@@ -77,11 +128,16 @@ Jev.define :urgent, "Requires immediate attention or action"
|
|
|
77
128
|
Jev.define :spam, "Unsolicited or unwanted promotional content"
|
|
78
129
|
Jev.define :angry, "Expresses anger or hostility"
|
|
79
130
|
|
|
131
|
+
Jev.define Email, :urgent, "Outage, customers cannot sign in"
|
|
132
|
+
Jev.define Comment, :urgent, "Legal takedown or self-harm"
|
|
133
|
+
|
|
80
134
|
Jev.definition(:urgent)
|
|
135
|
+
Jev.definition(Email, :urgent)
|
|
81
136
|
Jev.definitions
|
|
137
|
+
Jev.definitions(Email)
|
|
82
138
|
```
|
|
83
139
|
|
|
84
|
-
`define` replaces an existing name. `
|
|
140
|
+
`define` replaces an existing name in that scope. `Jev.feels?(text, Email, :urgent)` uses the Email definition, then falls back to the global `:urgent` if Email has none. `definitions` / `definitions(Email)` return frozen copies.
|
|
85
141
|
|
|
86
142
|
## Configuration
|
|
87
143
|
|
data/lib/jev/registry.rb
CHANGED
|
@@ -7,19 +7,28 @@ module Jev
|
|
|
7
7
|
@definitions = {}
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def define(name, description)
|
|
10
|
+
def define(scope, name, description)
|
|
11
11
|
key = name.to_sym
|
|
12
12
|
value = description.to_s.dup.freeze
|
|
13
|
-
@mutex.synchronize
|
|
13
|
+
@mutex.synchronize do
|
|
14
|
+
(@definitions[scope] ||= {})[key] = value
|
|
15
|
+
end
|
|
14
16
|
value
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
def fetch(name)
|
|
18
|
-
|
|
19
|
+
def fetch(name, scope: nil, fallback: true)
|
|
20
|
+
key = name.to_sym
|
|
21
|
+
@mutex.synchronize do
|
|
22
|
+
scoped = @definitions.dig(scope, key) if scope
|
|
23
|
+
return scoped if scoped
|
|
24
|
+
return unless fallback || scope.nil?
|
|
25
|
+
|
|
26
|
+
@definitions.dig(nil, key)
|
|
27
|
+
end
|
|
19
28
|
end
|
|
20
29
|
|
|
21
|
-
def all
|
|
22
|
-
@mutex.synchronize { @definitions.dup.freeze }
|
|
30
|
+
def all(scope = nil)
|
|
31
|
+
@mutex.synchronize { (@definitions[scope] || {}).dup.freeze }
|
|
23
32
|
end
|
|
24
33
|
|
|
25
34
|
def reset!
|
data/lib/jev/version.rb
CHANGED
data/lib/jev.rb
CHANGED
|
@@ -21,28 +21,45 @@ module Jev
|
|
|
21
21
|
@configuration = Configuration.new
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def define(
|
|
25
|
-
|
|
24
|
+
def define(scope_or_name, name_or_description, description = nil)
|
|
25
|
+
if scope_or_name.is_a?(Module)
|
|
26
|
+
raise ArgumentError, "description is required" if description.nil?
|
|
27
|
+
|
|
28
|
+
registry.define(scope_or_name, name_or_description, description)
|
|
29
|
+
else
|
|
30
|
+
raise ArgumentError, "wrong number of arguments (given 3, expected 2)" unless description.nil?
|
|
31
|
+
|
|
32
|
+
registry.define(nil, scope_or_name, name_or_description)
|
|
33
|
+
end
|
|
26
34
|
end
|
|
27
35
|
|
|
28
|
-
def definition(name)
|
|
29
|
-
|
|
36
|
+
def definition(scope_or_name, name = nil)
|
|
37
|
+
if name.nil?
|
|
38
|
+
registry.fetch(scope_or_name, scope: nil, fallback: false)
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError, "scope must be a Module" unless scope_or_name.is_a?(Module)
|
|
41
|
+
|
|
42
|
+
registry.fetch(name, scope: scope_or_name, fallback: false)
|
|
43
|
+
end
|
|
30
44
|
end
|
|
31
45
|
|
|
32
|
-
def definitions
|
|
33
|
-
|
|
46
|
+
def definitions(scope = nil)
|
|
47
|
+
raise ArgumentError, "scope must be a Module" unless scope.nil? || scope.is_a?(Module)
|
|
48
|
+
|
|
49
|
+
registry.all(scope)
|
|
34
50
|
end
|
|
35
51
|
|
|
36
52
|
def reset_definitions!
|
|
37
53
|
registry.reset!
|
|
38
54
|
end
|
|
39
55
|
|
|
40
|
-
def feels(text, predicate)
|
|
41
|
-
|
|
56
|
+
def feels(text, scope_or_predicate, predicate = nil)
|
|
57
|
+
scope, predicate = unpack_predicate(scope_or_predicate, predicate)
|
|
58
|
+
Client.new(configuration).probability(coerce_text(text), resolve(predicate, scope: scope))
|
|
42
59
|
end
|
|
43
60
|
|
|
44
|
-
def feels?(text, predicate, threshold: configuration.threshold)
|
|
45
|
-
feels(text, predicate) >= normalize_threshold(threshold)
|
|
61
|
+
def feels?(text, scope_or_predicate, predicate = nil, threshold: configuration.threshold)
|
|
62
|
+
feels(text, scope_or_predicate, predicate) >= normalize_threshold(threshold)
|
|
46
63
|
end
|
|
47
64
|
|
|
48
65
|
def normalize_threshold(value)
|
|
@@ -67,17 +84,32 @@ module Jev
|
|
|
67
84
|
text
|
|
68
85
|
end
|
|
69
86
|
|
|
70
|
-
def
|
|
87
|
+
def unpack_predicate(scope_or_predicate, predicate)
|
|
88
|
+
return [nil, scope_or_predicate] if predicate.nil?
|
|
89
|
+
raise ArgumentError, "scope must be a Module" unless scope_or_predicate.is_a?(Module)
|
|
90
|
+
|
|
91
|
+
[scope_or_predicate, predicate]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def resolve(predicate, scope: nil)
|
|
71
95
|
case predicate
|
|
72
96
|
when Symbol
|
|
73
|
-
|
|
74
|
-
raise(UndefinedDefinition,
|
|
97
|
+
registry.fetch(predicate, scope: scope) ||
|
|
98
|
+
raise(UndefinedDefinition, undefined_message(predicate, scope))
|
|
75
99
|
when String
|
|
76
100
|
predicate
|
|
77
101
|
else
|
|
78
102
|
raise ArgumentError, "predicate must be a Symbol or String"
|
|
79
103
|
end
|
|
80
104
|
end
|
|
105
|
+
|
|
106
|
+
def undefined_message(predicate, scope)
|
|
107
|
+
if scope
|
|
108
|
+
"Undefined Jev definition: #{predicate.inspect} for #{scope}"
|
|
109
|
+
else
|
|
110
|
+
"Undefined Jev definition: #{predicate.inspect}"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
81
113
|
end
|
|
82
114
|
|
|
83
115
|
reset_configuration!
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jev-feels
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Maxim Veysgeym
|
|
@@ -25,6 +25,7 @@ files:
|
|
|
25
25
|
- lib/feels.rb
|
|
26
26
|
- lib/feels/string.rb
|
|
27
27
|
- lib/jev-feels.rb
|
|
28
|
+
- lib/jev-feels/string.rb
|
|
28
29
|
- lib/jev.rb
|
|
29
30
|
- lib/jev/client.rb
|
|
30
31
|
- lib/jev/configuration.rb
|