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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb1c944edfc8044a07d64239c6452cf8717eee7a2878777b010ce06c7e328794
4
- data.tar.gz: 4c4092c5de15890bb9897934dffe82c515a236e441444caf016e282d20046060
3
+ metadata.gz: 125dde58282251c7692d030e90352e098cf1785bc38904cf6021098d073d2f8a
4
+ data.tar.gz: 6bdf7fb784623b94cde049148294a1513e59207ccde0fd683869bbb4cc639a6d
5
5
  SHA512:
6
- metadata.gz: c01170a2578338e6d8359399873593357c7896a2fa536eca538edd82830925d597e0bf6a6b5ffddb2fce804e9c974be6fe9a7eb7b62109d4078987f53743de75
7
- data.tar.gz: 41919c36db8eb4497f57acac8ee0c02bcca2f8cb5e7a5bf7b347dadda62253e80a7b5a20274f5db199ea5642e5eb98c82909ac8b9546920a336bc9e5c54d2e8e
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. `definitions` returns a frozen copy of the registry.
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 { @definitions[key] = value }
13
+ @mutex.synchronize do
14
+ (@definitions[scope] ||= {})[key] = value
15
+ end
14
16
  value
15
17
  end
16
18
 
17
- def fetch(name)
18
- @mutex.synchronize { @definitions[name.to_sym] }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jev
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "feels/string"
data/lib/jev.rb CHANGED
@@ -21,28 +21,45 @@ module Jev
21
21
  @configuration = Configuration.new
22
22
  end
23
23
 
24
- def define(name, description)
25
- registry.define(name, description)
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
- registry.fetch(name)
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
- registry.all
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
- Client.new(configuration).probability(coerce_text(text), resolve(predicate))
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 resolve(predicate)
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
- definition(predicate) ||
74
- raise(UndefinedDefinition, "Undefined Jev definition: #{predicate.inspect}")
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.1.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