attentive 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|