abstractor 4.4.1 → 4.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/views/abstractor/abstractor_abstractions/edit.html.haml +8 -8
- data/lib/abstractor/enum.rb +24 -0
- data/lib/abstractor/methods/models/abstractor_object_type.rb +11 -1
- data/lib/abstractor/methods/models/abstractor_subject.rb +98 -43
- data/lib/abstractor/parser.rb +26 -4
- data/lib/abstractor/setup.rb +3 -8
- data/lib/abstractor/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07d9074db71c7f0389203998331177b329015321
|
4
|
+
data.tar.gz: 266b2bfeb642c6613ff23e12da66d904c90723f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa9449c55a6b1600596d86fbaa55da291955a17e71a8f463cfa386687270e04654339d0e2e39441fbf7a418fb06d5e835124412c79092ae1ba6df6f092a2dd97
|
7
|
+
data.tar.gz: 1628fd3acdc7f26b12325cfb6666fed656937386faee9bb2b5de865f7d0744a2227e008f146fe2c454a7bfc450102f0ab74572f1a398e98023eb5a8be4507fa7
|
@@ -7,28 +7,28 @@
|
|
7
7
|
= abstraction_schema.display_name
|
8
8
|
.abstraction_edit_abstraction_value
|
9
9
|
- case abstraction_schema.abstractor_object_type.value
|
10
|
-
- when
|
10
|
+
- when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_DATE
|
11
11
|
= f.text_field :value, class: 'abstractor_datepicker'
|
12
|
-
- when
|
12
|
+
- when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_TEXT
|
13
13
|
= f.text_area :value
|
14
|
-
- when
|
14
|
+
- when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_STRING
|
15
15
|
= f.text_field :value
|
16
|
-
- when
|
16
|
+
- when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_NUMBER
|
17
17
|
= f.number_field :value
|
18
|
-
- when
|
18
|
+
- when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_RADIO_BUTTON_LIST
|
19
19
|
- values = abstraction_schema.abstractor_object_values.order('abstractor_abstraction_schema_object_values.display_order, abstractor_object_values.value')
|
20
20
|
- values.each do |value|
|
21
21
|
= f.radio_button :value, value.value
|
22
22
|
= f.label :value, value.value, value: value.value
|
23
23
|
= f.radio_button :value, '', {:style => 'display:none;' }
|
24
24
|
|
25
|
-
- when
|
25
|
+
- when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_LIST, Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_NUMBER_LIST
|
26
26
|
- values = abstraction_schema.abstractor_object_values.order('abstractor_abstraction_schema_object_values.display_order, abstractor_object_values.value')
|
27
27
|
= f.select :value, values.map{|s| [s.value, s.value]}, {:include_blank => true}, :class => "combobox"
|
28
|
-
- when
|
28
|
+
- when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_DYNAMIC_LIST
|
29
29
|
- values = abstractor_abstraction.about.send(abstractor_abstraction.abstractor_subject.dynamic_list_method).sort_by { |l| l[:value] }
|
30
30
|
= f.select :value, values.map{|s| [s[:value], s[:id]]}, {:include_blank => true}, :class => "combobox"
|
31
|
-
- when
|
31
|
+
- when Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_BOOLEAN
|
32
32
|
- ['true', 'false'].each do |value|
|
33
33
|
= f.radio_button :value, value
|
34
34
|
= f.label :value, value
|
data/lib/abstractor/enum.rb
CHANGED
@@ -21,6 +21,30 @@ module Abstractor
|
|
21
21
|
ABSTRACTOR_SUGGESTION_STATUS_ACCEPTED = 'Accepted'
|
22
22
|
ABSTRACTOR_SUGGESTION_STATUS_REJECTED = 'Rejected'
|
23
23
|
ABSTRACTOR_SUGGESTION_STATUSES = [ABSTRACTOR_SUGGESTION_STATUS_NEEDS_REVIEW, ABSTRACTOR_SUGGESTION_STATUS_ACCEPTED, ABSTRACTOR_SUGGESTION_STATUS_REJECTED]
|
24
|
+
|
24
25
|
ABSTRACTOR_GROUP_SENTINENTAL_SUBTYPE = 'sentinental'
|
26
|
+
|
27
|
+
ABSTRACTOR_OBJECT_TYPE_LIST = 'list'
|
28
|
+
ABSTRACTOR_OBJECT_TYPE_NUMBER = 'number'
|
29
|
+
ABSTRACTOR_OBJECT_TYPE_BOOLEAN = 'boolean'
|
30
|
+
ABSTRACTOR_OBJECT_TYPE_STRING = 'string'
|
31
|
+
ABSTRACTOR_OBJECT_TYPE_RADIO_BUTTON_LIST = 'radio button list'
|
32
|
+
ABSTRACTOR_OBJECT_TYPE_DATE = 'date'
|
33
|
+
ABSTRACTOR_OBJECT_TYPE_DYNAMIC_LIST = 'dynamic list'
|
34
|
+
ABSTRACTOR_OBJECT_TYPE_TEXT = 'text'
|
35
|
+
ABSTRACTOR_OBJECT_TYPE_NUMBER_LIST = 'number list'
|
36
|
+
ABSTRACTOR_OBJECT_TYPES = [
|
37
|
+
ABSTRACTOR_OBJECT_TYPE_LIST,
|
38
|
+
ABSTRACTOR_OBJECT_TYPE_NUMBER,
|
39
|
+
ABSTRACTOR_OBJECT_TYPE_BOOLEAN,
|
40
|
+
ABSTRACTOR_OBJECT_TYPE_STRING,
|
41
|
+
ABSTRACTOR_OBJECT_TYPE_RADIO_BUTTON_LIST,
|
42
|
+
ABSTRACTOR_OBJECT_TYPE_DATE,
|
43
|
+
ABSTRACTOR_OBJECT_TYPE_DYNAMIC_LIST,
|
44
|
+
ABSTRACTOR_OBJECT_TYPE_TEXT,
|
45
|
+
ABSTRACTOR_OBJECT_TYPE_NUMBER_LIST
|
46
|
+
]
|
47
|
+
|
48
|
+
NUMERIC_REGEX = '(?<object_value>\d+[\.,]*\d*[\.,]*\d*)'
|
25
49
|
end
|
26
50
|
end
|
@@ -8,7 +8,17 @@ module Abstractor
|
|
8
8
|
# Associations
|
9
9
|
base.send :has_many, :abstractor_abstraction_schemas
|
10
10
|
|
11
|
-
|
11
|
+
base.send(:include, InstanceMethods)
|
12
|
+
end
|
13
|
+
|
14
|
+
module InstanceMethods
|
15
|
+
def number?
|
16
|
+
self.value == Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_NUMBER
|
17
|
+
end
|
18
|
+
|
19
|
+
def number_list?
|
20
|
+
self.value == Abstractor::Enum::ABSTRACTOR_OBJECT_TYPE_NUMBER_LIST
|
21
|
+
end
|
12
22
|
end
|
13
23
|
end
|
14
24
|
end
|
@@ -238,65 +238,120 @@ module Abstractor
|
|
238
238
|
end
|
239
239
|
end
|
240
240
|
|
241
|
+
# Generates suggestions for name/value pairs.
|
242
|
+
#
|
243
|
+
# Tht method will detect sentenses in the source text that match any of the predicate variants.
|
244
|
+
# For each detected sentence, method would first try to abstract canonical name/value pair.
|
245
|
+
# If canonical match was not found, method would try to abstract sentinental match.
|
246
|
+
#
|
247
|
+
# @param [ActiveRecord::Base] about The entity to abstract. An instance of the class specified in the Abstractor::AbstractorSubject#subject_type attribute.
|
248
|
+
# @param [Abstractor::AbstractorAbstraction] abstractor_abstraction The instance of Abstractor::AbstractorAbstraction to make suggestions against.
|
249
|
+
# @param [Abstractor::AbstractorAbstractionSource] abstractor_abstraction_source The instance of the Abstractor::AbstractorAbstractionSource that provides the custom method to invoke on the abstractable entity to make custom suggestions.
|
250
|
+
# @return [void]
|
241
251
|
def abstract_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
|
242
|
-
abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
|
243
|
-
abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
|
244
|
-
create_unknown_abstractor_suggestion_name_only(about, abstractor_abstraction, abstractor_abstraction_source)
|
245
|
-
create_unknown_abstractor_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
|
246
|
-
end
|
247
|
-
|
248
|
-
def abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
|
249
252
|
abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
|
250
253
|
abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
|
251
254
|
parser = Abstractor::Parser.new(abstractor_text)
|
255
|
+
|
252
256
|
abstractor_abstraction_schema.predicate_variants.each do |predicate_variant|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
257
|
+
ranges = parser.range_all(Regexp.escape(predicate_variant), word_boundary: false)
|
258
|
+
ranges.each do |range|
|
259
|
+
sentence = parser.find_sentence(range)
|
260
|
+
if sentence
|
261
|
+
is_abstracted = abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source, source, parser, sentence, predicate_variant)
|
262
|
+
abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source, source, parser, sentence, predicate_variant) unless is_abstracted
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
create_unknown_abstractor_suggestion_name_only(about, abstractor_abstraction, abstractor_abstraction_source)
|
268
|
+
create_unknown_abstractor_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
|
269
|
+
end
|
260
270
|
|
261
|
-
|
262
|
-
|
271
|
+
def abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source, source, parser, sentence, predicate_variant)
|
272
|
+
is_abstracted = false
|
273
|
+
if abstractor_abstraction_schema.abstractor_object_type && (abstractor_abstraction_schema.abstractor_object_type.number? || abstractor_abstraction_schema.abstractor_object_type.number_list?)
|
274
|
+
object_regex = Abstractor::Enum::NUMERIC_REGEX
|
275
|
+
|
276
|
+
match_values = ["#{Regexp.escape(predicate_variant)}:\s*#{object_regex}", "#{Regexp.escape(predicate_variant)}#{object_regex}"]
|
277
|
+
match_values.each do |match_value|
|
278
|
+
matches = parser.sentence_match_scan(sentence[:sentence], match_value, word_boundary: true).uniq
|
279
|
+
if abstractor_abstraction_schema.abstractor_object_type.number_list?
|
280
|
+
# filter matched numbers by list of available values
|
281
|
+
abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
|
282
|
+
abstractor_object_value.object_variants.each do |object_variant|
|
283
|
+
matches.each do |match|
|
284
|
+
if object_variant == match[:object_value]
|
285
|
+
suggest(abstractor_abstraction, abstractor_abstraction_source, match.to_s, match.to_s, source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
else
|
291
|
+
matches.each do |match|
|
292
|
+
is_abstracted = suggest(abstractor_abstraction, abstractor_abstraction_source, match.to_s, match.to_s, source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], match[:object_value], nil, nil, nil, nil)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
else
|
297
|
+
abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
|
298
|
+
abstractor_object_value.object_variants.each do |object_variant|
|
299
|
+
match_values = ["#{Regexp.escape(predicate_variant)}:\s*#{Regexp.escape(object_variant)}", "#{Regexp.escape(predicate_variant)}#{Regexp.escape(object_variant)}"]
|
300
|
+
match_values.each do |match_value|
|
301
|
+
matches = parser.sentence_scan(sentence[:sentence], match_value, word_boundary: true).uniq
|
263
302
|
matches.each do |match|
|
264
|
-
suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], source[:
|
303
|
+
is_abstracted = suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
|
265
304
|
end
|
266
305
|
end
|
267
306
|
end
|
268
307
|
end
|
269
308
|
end
|
309
|
+
is_abstracted
|
270
310
|
end
|
271
311
|
|
272
|
-
def abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
)
|
293
|
-
if !reject
|
294
|
-
suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
|
295
|
-
end
|
296
|
-
end
|
312
|
+
def abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source, source, parser, sentence, predicate_variant)
|
313
|
+
is_abstracted = false
|
314
|
+
if abstractor_abstraction_schema.abstractor_object_type && (abstractor_abstraction_schema.abstractor_object_type.number? || abstractor_abstraction_schema.abstractor_object_type.number_list?)
|
315
|
+
object_regex = object_regex = Abstractor::Enum::NUMERIC_REGEX
|
316
|
+
match = parser.match_sentence(sentence[:sentence], object_regex)
|
317
|
+
if match
|
318
|
+
scoped_sentence = Abstractor::NegationDetection.parse_negation_scope(sentence[:sentence])
|
319
|
+
reject = (
|
320
|
+
Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], predicate_variant) ||
|
321
|
+
Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], predicate_variant) ||
|
322
|
+
Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], match[:object_value]) ||
|
323
|
+
Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], match[:object_value])
|
324
|
+
)
|
325
|
+
if !reject
|
326
|
+
if abstractor_abstraction_schema.abstractor_object_type.number_list?
|
327
|
+
# filter matched numbers by list of available values
|
328
|
+
abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
|
329
|
+
abstractor_object_value.object_variants.each do |object_variant|
|
330
|
+
if object_variant == match[:object_value]
|
331
|
+
suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
|
297
332
|
end
|
298
333
|
end
|
299
334
|
end
|
335
|
+
else
|
336
|
+
is_abstracted = suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], match[:object_value], nil, nil, nil, nil)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
else
|
341
|
+
abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
|
342
|
+
abstractor_object_value.object_variants.each do |object_variant|
|
343
|
+
match = parser.match_sentence(sentence[:sentence], Regexp.escape(object_variant))
|
344
|
+
if match
|
345
|
+
scoped_sentence = Abstractor::NegationDetection.parse_negation_scope(sentence[:sentence])
|
346
|
+
reject = (
|
347
|
+
Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], predicate_variant) ||
|
348
|
+
Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], predicate_variant) ||
|
349
|
+
Abstractor::NegationDetection.negated_match_value?(scoped_sentence[:scoped_sentence], object_variant) ||
|
350
|
+
Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], object_variant)
|
351
|
+
)
|
352
|
+
if !reject
|
353
|
+
is_abstracted = suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
|
354
|
+
end
|
300
355
|
end
|
301
356
|
end
|
302
357
|
end
|
@@ -377,7 +432,7 @@ module Abstractor
|
|
377
432
|
def create_unknown_abstractor_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
|
378
433
|
#Create an 'unknown' suggestion based on matching nothing only if we have not made a suggstion
|
379
434
|
abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
|
380
|
-
if abstractor_abstraction.abstractor_suggestions(true).select { |abstractor_suggestion| abstractor_suggestion.unknown != true }.empty?
|
435
|
+
if abstractor_abstraction.abstractor_suggestions(true).select { |abstractor_suggestion| abstractor_suggestion.unknown != true || abstractor_suggestion.unknown == true}.empty?
|
381
436
|
suggest(abstractor_abstraction, abstractor_abstraction_source, nil, nil, source[:source_id], source[:source_type].to_s, source[:source_method],source[:section_name], nil, true, nil, nil, nil)
|
382
437
|
end
|
383
438
|
end
|
data/lib/abstractor/parser.rb
CHANGED
@@ -28,8 +28,8 @@ module Abstractor
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
options[:word_boundary] = true
|
31
|
+
def scan(token, options = {})
|
32
|
+
options[:word_boundary] = true if options[:word_boundary].nil?
|
33
33
|
regular_expression = prepare_token(token, options)
|
34
34
|
at = prepare_abstractor_text
|
35
35
|
if (regular_expression.nil? || at.nil?)
|
@@ -39,13 +39,35 @@ module Abstractor
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
def sentence_scan(sentence, token, options = {})
|
43
|
+
options[:word_boundary] = true if options[:word_boundary].nil?
|
44
|
+
regular_expression = prepare_token(token, options)
|
45
|
+
if (regular_expression.nil? || sentence.nil?)
|
46
|
+
[]
|
47
|
+
else
|
48
|
+
sentence.scan(regular_expression)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def sentence_match_scan(sentence, token, options = {})
|
53
|
+
options[:word_boundary] = true if options[:word_boundary].nil?
|
54
|
+
regular_expression = prepare_token(token, options)
|
55
|
+
if (regular_expression.nil? || sentence.nil?)
|
56
|
+
[]
|
57
|
+
else
|
58
|
+
# http://stackoverflow.com/questions/6804557/how-do-i-get-the-match-data-for-all-occurrences-of-a-ruby-regular-expression-in
|
59
|
+
sentence.to_enum(:scan,regular_expression).map{ Regexp.last_match }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
42
63
|
def match(token)
|
43
64
|
regular_expression = prepare_token(token)
|
44
65
|
prepare_abstractor_text.match(regular_expression) unless regular_expression.nil?
|
45
66
|
end
|
46
67
|
|
47
|
-
def range_all(token)
|
48
|
-
|
68
|
+
def range_all(token, options = {})
|
69
|
+
options[:word_boundary] = true if options[:word_boundary].nil?
|
70
|
+
regular_expression = prepare_token(token, options)
|
49
71
|
prepare_abstractor_text.range_all(regular_expression) unless regular_expression.nil?
|
50
72
|
end
|
51
73
|
|
data/lib/abstractor/setup.rb
CHANGED
@@ -2,14 +2,9 @@ module Abstractor
|
|
2
2
|
module Setup
|
3
3
|
def self.system
|
4
4
|
puts 'Setting up Abstractor::AbstractorObjectType'
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
Abstractor::AbstractorObjectType.where(value: 'string').first_or_create
|
9
|
-
Abstractor::AbstractorObjectType.where(value: 'radio button list').first_or_create
|
10
|
-
Abstractor::AbstractorObjectType.where(value: 'date').first_or_create
|
11
|
-
Abstractor::AbstractorObjectType.where(value: 'dynamic list').first_or_create
|
12
|
-
Abstractor::AbstractorObjectType.where(value: 'text').first_or_create
|
5
|
+
Abstractor::Enum::ABSTRACTOR_OBJECT_TYPES.each do |abstractor_object_type|
|
6
|
+
Abstractor::AbstractorObjectType.where(value: abstractor_object_type).first_or_create
|
7
|
+
end
|
13
8
|
|
14
9
|
puts 'Setting up Abstractor::AbstractorRuleType'
|
15
10
|
Abstractor::AbstractorRuleType.where(name: 'name/value', description:'search for value associated with name').first_or_create
|
data/lib/abstractor/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: abstractor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.4.
|
4
|
+
version: 4.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Gurley, Yulia Bushmanova
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -845,7 +845,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
845
845
|
version: '0'
|
846
846
|
requirements: []
|
847
847
|
rubyforge_project:
|
848
|
-
rubygems_version: 2.
|
848
|
+
rubygems_version: 2.2.2
|
849
849
|
signing_key:
|
850
850
|
specification_version: 4
|
851
851
|
summary: A Rails engine gem for deriving discrete data points from narrative text
|