attentive 0.3.1 → 0.3.2
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/Rakefile +1 -1
- data/lib/attentive/duration.rb +35 -0
- data/lib/attentive/entities/core/date/duration/units.rb +29 -0
- data/lib/attentive/entities/core/date/duration.rb +25 -0
- data/lib/attentive/entities/core/date/relative/future.rb +1 -1
- data/lib/attentive/entities/core/date/relative/past.rb +1 -1
- data/lib/attentive/entities/core/date.rb +1 -0
- data/lib/attentive/entity.rb +2 -2
- data/lib/attentive/errors.rb +0 -3
- data/lib/attentive/listener.rb +1 -1
- data/lib/attentive/message.rb +1 -0
- data/lib/attentive/tokenizer.rb +3 -18
- data/lib/attentive/tokens/any_of.rb +12 -0
- data/lib/attentive/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed9424d444fc7b37aa1ad0e003fa687a00fc5aa6
|
4
|
+
data.tar.gz: 031fc365d1be4944cd5c612caa218c7d64cc2e97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 015a425a258acc78e6d0d5b0d99c8af95c0af16ced679de556863219d99a6c59610af1353bf2f92b777b91f69a7fbb727304baa77b7301b5547b842e921d97c1
|
7
|
+
data.tar.gz: 4f4fc07e43650c108b8f01511485716a17f360d6c8a7d6d2e76ba4fbb81379b4bbcfaa79007f2d280aa45b0dc60c6f214c27c6062b8b28da070cf7bc175960da
|
data/Rakefile
CHANGED
@@ -25,7 +25,7 @@ namespace :compile do
|
|
25
25
|
# the first value is the contraction.
|
26
26
|
# the remaining values are possible phrases that match it
|
27
27
|
phrases = line.downcase.chomp.split("\t")
|
28
|
-
raise "#{line.inspect} must have
|
28
|
+
raise "#{line.inspect} must have at least two values" unless phrases.length >= 2
|
29
29
|
|
30
30
|
substitutions[phrases.shift] = phrases
|
31
31
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Attentive
|
2
|
+
class Duration < Struct.new(:years, :months, :days)
|
3
|
+
|
4
|
+
def initialize(attributes)
|
5
|
+
super(
|
6
|
+
attributes.fetch(:years, 0),
|
7
|
+
attributes.fetch(:months, 0),
|
8
|
+
attributes.fetch(:days, 0))
|
9
|
+
end
|
10
|
+
|
11
|
+
def +(other)
|
12
|
+
self.class.new(
|
13
|
+
years: years + other.years,
|
14
|
+
months: months + other.months,
|
15
|
+
days: days + other.days)
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
phrases = []
|
20
|
+
phrases.push "#{years} years" if years > 0
|
21
|
+
phrases.push "#{months} months" if months > 0
|
22
|
+
phrases.push "#{days} days" if days > 0
|
23
|
+
"<#{phrases.join(" ")}>"
|
24
|
+
end
|
25
|
+
|
26
|
+
def after(date)
|
27
|
+
(date >> (years * 12 + months)) + days
|
28
|
+
end
|
29
|
+
|
30
|
+
def before(date)
|
31
|
+
(date >> -(years * 12 + months)) - days
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "attentive/entity"
|
2
|
+
require "date"
|
3
|
+
|
4
|
+
Attentive::Entity.define "core.date.duration.units",
|
5
|
+
"day",
|
6
|
+
"days",
|
7
|
+
"week",
|
8
|
+
"wk",
|
9
|
+
"weeks",
|
10
|
+
"wks",
|
11
|
+
"month",
|
12
|
+
"mo",
|
13
|
+
"months",
|
14
|
+
"mos",
|
15
|
+
"year",
|
16
|
+
"yr",
|
17
|
+
"years",
|
18
|
+
"yrs",
|
19
|
+
published: false do |match|
|
20
|
+
|
21
|
+
case match.phrase
|
22
|
+
when "day", "days" then :days
|
23
|
+
when "week", "wk", "weeks", "wks" then :weeks
|
24
|
+
when "month", "mo", "months", "mos" then :months
|
25
|
+
when "year", "yr", "years", "yrs" then :years
|
26
|
+
else
|
27
|
+
nomatch!
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "attentive/entity"
|
2
|
+
require "attentive/duration"
|
3
|
+
require "attentive/entities/core/date/duration/units"
|
4
|
+
|
5
|
+
Attentive::Entity.define "core.date.duration.single",
|
6
|
+
"{{n:core.number.integer.positive}} {{unit:core.date.duration.units}}",
|
7
|
+
published: false do |match|
|
8
|
+
|
9
|
+
unit = match["unit"]
|
10
|
+
n = match["n"]
|
11
|
+
unit, n = [:days, n * 7] if unit == :weeks
|
12
|
+
Attentive::Duration.new(unit => n)
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
Attentive::Entity.define "core.date.duration",
|
17
|
+
"{{a:core.date.duration.single}} {{b:core.date.duration}}",
|
18
|
+
"{{a:core.date.duration.single}} and {{b:core.date.duration}}",
|
19
|
+
"{{a:core.date.duration.single}}" do |match|
|
20
|
+
|
21
|
+
a = match["a"]
|
22
|
+
a += match["b"] if match.matched?("b")
|
23
|
+
a
|
24
|
+
|
25
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "attentive/entities/core/date/month"
|
2
2
|
require "attentive/entities/core/date/wday"
|
3
|
+
require "attentive/entities/core/date/duration"
|
3
4
|
require "attentive/entities/core/date/relative"
|
4
5
|
require "attentive/entities/core/date/partial"
|
5
6
|
require "attentive/entities/core/date/explicit"
|
data/lib/attentive/entity.rb
CHANGED
@@ -32,7 +32,7 @@ module Attentive
|
|
32
32
|
|
33
33
|
create! entity_name do |entity_klass|
|
34
34
|
entity_klass.phrases = phrases.map do |phrase|
|
35
|
-
Attentive::Tokenizer.tokenize(phrase, entities: true, regexps: true
|
35
|
+
Attentive::Tokenizer.tokenize(phrase, entities: true, regexps: true)
|
36
36
|
end
|
37
37
|
entity_klass.published = options.fetch(:published, true)
|
38
38
|
entity_klass.send :define_method, :_value_from_match, &block if block_given?
|
@@ -50,8 +50,8 @@ module Attentive
|
|
50
50
|
entity_symbol = entity_name.to_sym
|
51
51
|
entity_klass = Class.new(self)
|
52
52
|
entity_klass.token_name = entity_symbol
|
53
|
-
yield entity_klass
|
54
53
|
Entity.register! entity_symbol, entity_klass
|
54
|
+
yield entity_klass
|
55
55
|
end
|
56
56
|
|
57
57
|
def register!(entity_name, entity_klass)
|
data/lib/attentive/errors.rb
CHANGED
data/lib/attentive/listener.rb
CHANGED
data/lib/attentive/message.rb
CHANGED
@@ -6,6 +6,7 @@ module Attentive
|
|
6
6
|
attr_reader :contexts, :text
|
7
7
|
|
8
8
|
def initialize(text, params={})
|
9
|
+
raise ArgumentError, "Message cannot be initialized without 'text'" unless text
|
9
10
|
@text = text
|
10
11
|
@contexts = Set.new(params.fetch(:contexts, []))
|
11
12
|
contexts << :conversation if tokens.grep(Attentive::Tokens::Invocation).any?
|
data/lib/attentive/tokenizer.rb
CHANGED
@@ -33,10 +33,6 @@ module Attentive
|
|
33
33
|
options.fetch(:substitutions, true)
|
34
34
|
end
|
35
35
|
|
36
|
-
def fail_if_ambiguous?
|
37
|
-
!options.fetch(:ambiguous, true)
|
38
|
-
end
|
39
|
-
|
40
36
|
|
41
37
|
|
42
38
|
def tokenize
|
@@ -80,8 +76,6 @@ module Attentive
|
|
80
76
|
end
|
81
77
|
end
|
82
78
|
|
83
|
-
fail_if_ambiguous!(message, tokens) if fail_if_ambiguous?
|
84
|
-
|
85
79
|
Attentive::Phrase.new(tokens)
|
86
80
|
end
|
87
81
|
|
@@ -132,7 +126,7 @@ module Attentive
|
|
132
126
|
end
|
133
127
|
|
134
128
|
def match_whitespace_at(i)
|
135
|
-
whitespace = chars[i]
|
129
|
+
whitespace = chars[i].dup
|
136
130
|
while (i += 1) < chars.length
|
137
131
|
break unless WHITESPACE === chars[i]
|
138
132
|
whitespace << chars[i]
|
@@ -142,7 +136,7 @@ module Attentive
|
|
142
136
|
|
143
137
|
def match_number_at(i)
|
144
138
|
return false if CONDITIONAL_NUMBER_START === chars[i] && !(NUMBER === chars[i + 1])
|
145
|
-
number = chars[i]
|
139
|
+
number = chars[i].dup
|
146
140
|
while (i += 1) < chars.length
|
147
141
|
break unless NUMBER === chars[i] || (CONDITIONAL_NUMBER === chars[i] && NUMBER === chars[i + 1])
|
148
142
|
number << chars[i]
|
@@ -151,7 +145,7 @@ module Attentive
|
|
151
145
|
end
|
152
146
|
|
153
147
|
def match_word_at(i)
|
154
|
-
word = chars[i]
|
148
|
+
word = chars[i].dup
|
155
149
|
while (i += 1) < chars.length
|
156
150
|
break unless WORD === chars[i]
|
157
151
|
word << chars[i]
|
@@ -207,15 +201,6 @@ module Attentive
|
|
207
201
|
"‘" => "'",
|
208
202
|
"’" => "'" }.freeze
|
209
203
|
|
210
|
-
def fail_if_ambiguous!(phrase, tokens)
|
211
|
-
ambiguous_token = tokens.find(&:ambiguous?)
|
212
|
-
return unless ambiguous_token
|
213
|
-
|
214
|
-
raise Attentive::AmbiguousPhraseError.new(
|
215
|
-
"The phrase #{phrase.inspect} is ambiguous. " <<
|
216
|
-
"Please use #{ambiguous_token.possibilities.map(&:inspect).join(" or ")}")
|
217
|
-
end
|
218
|
-
|
219
204
|
end
|
220
205
|
end
|
221
206
|
|
@@ -18,6 +18,18 @@ module Attentive
|
|
18
18
|
true
|
19
19
|
end
|
20
20
|
|
21
|
+
def matches?(cursor)
|
22
|
+
possibilities.each do |phrase|
|
23
|
+
cursor_copy = cursor.new_from_here
|
24
|
+
match = Attentive::Matcher.new(phrase, cursor_copy).match!
|
25
|
+
if match
|
26
|
+
cursor.advance cursor_copy.pos
|
27
|
+
return match.to_h
|
28
|
+
end
|
29
|
+
end
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
21
33
|
end
|
22
34
|
end
|
23
35
|
end
|
data/lib/attentive/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attentive
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bob Lail
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thread_safe
|
@@ -156,8 +156,11 @@ files:
|
|
156
156
|
- lib/attentive/composite_entity.rb
|
157
157
|
- lib/attentive/config.rb
|
158
158
|
- lib/attentive/cursor.rb
|
159
|
+
- lib/attentive/duration.rb
|
159
160
|
- lib/attentive/entities/core.rb
|
160
161
|
- lib/attentive/entities/core/date.rb
|
162
|
+
- lib/attentive/entities/core/date/duration.rb
|
163
|
+
- lib/attentive/entities/core/date/duration/units.rb
|
161
164
|
- lib/attentive/entities/core/date/explicit.rb
|
162
165
|
- lib/attentive/entities/core/date/future.rb
|
163
166
|
- lib/attentive/entities/core/date/month.rb
|
@@ -220,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
220
223
|
version: '0'
|
221
224
|
requirements: []
|
222
225
|
rubyforge_project:
|
223
|
-
rubygems_version: 2.
|
226
|
+
rubygems_version: 2.5.1
|
224
227
|
signing_key:
|
225
228
|
specification_version: 4
|
226
229
|
summary: A library for matching messages to natural-language listeners
|