abstractor 2.0.1 → 2.1.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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MjEzMmZmNTcyYjc4MjZkMjQyZjA5MWE5NzQxYWExMDhhYWExNDcwZQ==
4
+ MWUzYjczYWRlYjNkMzRiNzc2YTRjYjQ3YjIyM2IyZDAwYjE2ZGNkZg==
5
5
  data.tar.gz: !binary |-
6
- OWNkMzRkZjZiNDU5ZjQ3NDQ5Y2YyMjk0NzhmMGQxNGJmMTA1MGYwNA==
6
+ MDczMzEzODRiNGE1ZjM5NmYyYmQxM2Q1ODUyOGQ5NGQ2N2Y4MjY4Yw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZTJkYjRiZDg4ZjA2NzM2MjYzNjU5NWQzMjA5MmQ3MmFlNzI5YjFhZDhlN2I1
10
- NGE4NzU4MTA2YTEyNDU0YTk2NDcxZjhlYjhiY2U3ZTFjYzliNDg0OWFlYjNj
11
- NzQ3NWU1YTk1NTU4NTc1NTU2ZTZiMDZlZDliOGVmZjg5MDc0N2M=
9
+ MTRlNzg5ZDFiOTlhMDBmMDc4YmNhZDkyYTY1Nzc0YjU0ZmEzYWJmYmY1YzEz
10
+ OGRkMGE2MTkwZDUzNTcxODRjZjcwYTI4ODlmN2NlMzExN2U4YjBiNzM0ZTI0
11
+ MzFlMTkzOWU2NDc4MWZkOTBhYmMzMDJkZmZiYzBhMWI2MTg4OWI=
12
12
  data.tar.gz: !binary |-
13
- N2FiMTI4YmEwYTlkZTE2NGFmMzU1NDUyODE3NGNjODdiNjA2YjU1NTYyY2Yz
14
- MmNkN2ZlODY5MzY1ZTA4ODQ3NzQ1MDM1M2QyNDlhYTE1MmQ0NDUyOGM0M2Ni
15
- NjlkN2EyNDA1OWE2YTUzNTMxMTkwMDAxMzU1MGFjY2UyMGY0ZjY=
13
+ NGY1YTAzNmZiYWU4NWUxZThiOTExZmQxYWMyYjcwYTVkNTVkZTQzZThjMzc1
14
+ MTAxYmFkNmYzMjQ3ZjUyOGYyMWFhZTgzODAyMWI3OWIwMDJmYWY3ZjE0N2Fi
15
+ NTZhOWJjNjVmMDgzN2QxYzEyZDA3NmRmZjc4YmE5ODRiMWNjYzI=
@@ -330,4 +330,12 @@ span.tooltip_img {
330
330
 
331
331
  .indirect_source {
332
332
  margin-bottom: 1em;
333
+ }
334
+
335
+ .abstractor_suggestion_values .custom_explanation {
336
+ margin-top: .5em;
337
+ }
338
+
339
+ .abstractor_suggestion_values .custom_explanation label {
340
+ font-weight: bold !important;
333
341
  }
@@ -47,6 +47,12 @@
47
47
  = Abstractor::UserInterface.highlight(simple_format(abstractable_from_column.clone), abstractor_suggestion_source.sentence_match_value.strip)
48
48
  - else
49
49
  = simple_format(abstractable_from_column.clone)
50
+ - if abstractor_suggestion_source.custom_explanation
51
+ .custom_explanation
52
+ %label
53
+ Explanation:
54
+ .explanation_text
55
+ = abstractor_suggestion_source.custom_explanation
50
56
  .column-3
51
57
  - values = Abstractor::AbstractorSuggestionStatus.all.sort_by(&:name).map{|s| [s.name, s.id] }
52
58
  - values.each do |value|
@@ -43,7 +43,7 @@
43
43
  = f.label :unknown, 'unknown'
44
44
  .column-3
45
45
  - abstractor_abstraction = f.object
46
- - abstraction_sources = abstractor_abstraction.abstractor_subject.abstractor_abstraction_sources.select { |s| s.abstractor_abstraction_source_type.name == 'nlp suggestion' }
46
+ - abstraction_sources = abstractor_abstraction.abstractor_subject.abstractor_abstraction_sources.select { |s| s.abstractor_abstraction_source_type.name != 'indirect' }
47
47
  - abstraction_sources.each do |abstraction_source|
48
48
  - abstraction_source.normalize_from_method_to_sources(abstractor_abstraction.about).each do |source|
49
49
  - dom_id = "#{abstraction_source.id}_#{source[:source_type]}_#{source[:source_id]}_#{source[:source_method]}"
@@ -0,0 +1,5 @@
1
+ class AddCustomExplanationToAbstractorSuggestionSources < ActiveRecord::Migration
2
+ def change
3
+ add_column :abstractor_suggestion_sources, :custom_explanation, :string
4
+ end
5
+ end
@@ -49,10 +49,28 @@ module Abstractor
49
49
  abstractor_abstraction_group
50
50
  end
51
51
 
52
- def abstractor_abstractions_by_abstractor_suggestion_status(abstractor_suggestion_statuses)
53
- abstractor_abstractions.map(&:abstractor_suggestions).flatten.select { |as| Array.new(abstractor_suggestion_statuses).any? { |abstractor_suggestion_status| as.abstractor_suggestion_status == abstractor_suggestion_status } }
52
+ ##
53
+ # Returns all abstraction for the abstractable entity by abstractor_abstraction_status:
54
+ #
55
+ # * 'needs_review': Filter abstractions without a determined value (value, unknown or not_applicable).
56
+ # * 'reviewed': Filter abstractions having a determined value (value, unknown or not_applicable).
57
+ #
58
+ # @param [String] abstractor_abstraction_status Filter abstractions that need review or are reviews.
59
+ # @return [ActiveRecord::Relation] List of [Abstractor::AbstractorAbstraction].
60
+ def abstractor_abstractions_by_abstractor_abstraction_status(abstractor_abstraction_status)
61
+ case abstractor_abstraction_status
62
+ when 'needs_review'
63
+ abstractor_abstractions.select { |abstractor_abstraction| abstractor_abstraction.value.blank? && abstractor_abstraction.unknown.blank? && abstractor_abstraction.not_applicable.blank? }
64
+ when 'reviewed'
65
+ abstractor_abstractions.select { |abstractor_abstraction| !abstractor_abstraction.value.blank? || !abstractor_abstraction.unknown.blank? || !abstractor_abstraction.not_applicable.blank? }
66
+ end
54
67
  end
55
68
 
69
+ ##
70
+ # Removes all abstractions, suggestions and indirect sources for the abstractable entity. Optionally filtred to only 'unreviewd' abstractions.
71
+ #
72
+ # @param [Boolean] only_unreviewed Instructs whther to confine removal to only 'unreviewd' abstractions.
73
+ # @return [void]
56
74
  def remove_abstractions(only_unreviewed = true)
57
75
  abstractor_abstractions.each do |abstractor_abstraction|
58
76
  if !only_unreviewed || (only_unreviewed && abstractor_abstraction.unreviewed?)
@@ -61,6 +79,9 @@ module Abstractor
61
79
  abstractor_suggestion.abstractor_suggestion_object_value.destroy if abstractor_suggestion.abstractor_suggestion_object_value
62
80
  abstractor_suggestion.destroy
63
81
  end
82
+ abstractor_abstraction.abstractor_indirect_sources.each do |abstractor_indirect_source|
83
+ abstractor_indirect_source.destroy
84
+ end
64
85
  abstractor_abstraction.destroy
65
86
  end
66
87
  end
@@ -79,9 +100,9 @@ module Abstractor
79
100
  def by_abstractor_abstraction_status(abstractor_abstraction_status)
80
101
  case abstractor_abstraction_status
81
102
  when 'needs_review'
82
- where(["EXISTS (SELECT 1 FROM abstractor_subjects asb JOIN abstractor_abstractions aa ON asb.id = aa.abstractor_subject_id AND asb.subject_type = '#{self.to_s}' WHERE #{self.table_name}.id = aa.about_id AND aa.value IS NULL AND (aa.unknown IS NULL OR aa.unknown = ?) AND (aa.not_applicable IS NULL OR aa.not_applicable = ?))", false, false])
103
+ where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND (aa.value IS NULL OR aa.value = '') AND (aa.unknown IS NULL OR aa.unknown = ?) AND (aa.not_applicable IS NULL OR aa.not_applicable = ?))", false, false])
83
104
  when 'reviewed'
84
- where(["EXISTS (SELECT 1 FROM abstractor_subjects asb JOIN abstractor_abstractions aa ON asb.id = aa.abstractor_subject_id AND asb.subject_type = '#{self.to_s}' WHERE #{self.table_name}.id = aa.about_id) AND NOT EXISTS (SELECT 1 FROM abstractor_subjects asb JOIN abstractor_abstractions aa ON asb.id = aa.abstractor_subject_id AND asb.subject_type = '#{self.to_s}'WHERE #{self.table_name}.id = aa.about_id AND aa.value IS NOT NULL AND aa.unknown != ? AND aa.not_applicable != ?)", true, true])
105
+ where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id) AND NOT EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND COALESCE(aa.value, '') = '' AND COALESCE(aa.unknown, ?) != ? AND COALESCE(aa.not_applicable, ?) != ?)", false, true, false, true])
85
106
  else
86
107
  where(nil)
87
108
  end
@@ -12,6 +12,10 @@ module Abstractor
12
12
  @abstractor_abstraction_group.abstractor_subject_group.abstractor_subjects.each do |abstractor_subject|
13
13
  abstraction = abstractor_subject.abstractor_abstractions.build(about_id: params[:about_id], about_type: params[:about_type])
14
14
  abstraction.build_abstractor_abstraction_group_member(abstractor_abstraction_group: @abstractor_abstraction_group)
15
+ abstraction.abstractor_subject.abstractor_abstraction_sources.select { |s| s.abstractor_abstraction_source_type.name == 'indirect' }.each do |abstractor_abstraction_source|
16
+ source = abstractor_subject.subject_type.constantize.find(params[:about_id]).send(abstractor_abstraction_source.from_method)
17
+ abstraction.abstractor_indirect_sources.build(abstractor_abstraction_source: abstractor_abstraction_source, source_type: source[:source_type], source_method: source[:source_method])
18
+ end
15
19
  abstraction.save!
16
20
  end
17
21
 
@@ -66,9 +66,12 @@ module Abstractor
66
66
  end
67
67
  end
68
68
 
69
+ ##
70
+ # Determines if the abstraction has been reviewed.
71
+ #
72
+ # @return [Boolean]
69
73
  def unreviewed?
70
- abstractor_suggestion_status_needs_review = Abstractor::AbstractorSuggestionStatus.where(name: 'Needs review').first
71
- abstractor_suggestions.any? { |abstractor_suggestion| abstractor_suggestion.abstractor_suggestion_status == abstractor_suggestion_status_needs_review }
74
+ (value.blank? && unknown.blank? && not_applicable.blank?)
72
75
  end
73
76
 
74
77
  ##
@@ -64,7 +64,7 @@ module Abstractor
64
64
  # method on the abstractable enttiy specified in Abstractor::AbstractorAbstractionSource#from_method.
65
65
  # The method should return a hash with the following keys populated:
66
66
  #
67
- # * [Array<ActiveRecord::Base>] :sources An array of active record objects that constitute the list of indirect sources.
67
+ # * [Array <ActiveRecord::Base>] :sources An array of active record objects that constitute the list of indirect sources.
68
68
  # * [Symbol] :source_id A method specifying the primary key of each member in sources.
69
69
  # * [Symbol] :source_method A method specifying the source text of each member in sources.
70
70
  #
@@ -94,7 +94,6 @@ module Abstractor
94
94
  # @param [Abstractor::AbstractorAbstraction] abstractor_abstraction The instance of Abstractor::AbstractorAbstraction to make suggestions against.
95
95
  # @param [Abstractor::AbstractorAbstractionSource] abstractor_abstraction_source The instance of the Abstractor::AbstractorAbstractionSource that provides the rule type and from method to make nlp suggestions.
96
96
  # @return [void]
97
-
98
97
  def abstract_nlp_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
99
98
  case abstractor_abstraction_source.abstractor_rule_type.name
100
99
  when 'name/value'
@@ -107,24 +106,30 @@ module Abstractor
107
106
  end
108
107
 
109
108
  # Creates instances of Abstractor::AbstractorSuggestion and Abstractor::AbstractorSuggestionSource
110
- # based on calling the method configured by the AbstractorAbstractionSource#custom_method attribute.
109
+ # based on calling the method configured by the AbstractorAbstractionSource#custom_method attribute.
111
110
  # The method is called on the abstractable entity passed via the about parameter.
112
111
  #
113
112
  # Setting up an Abstractor::AbstractorSubject with an AbstractorAbstractionSource
114
113
  # with an AbstractorAbstractionSource#abstractor_abstraction_source_type attribute
115
114
  # set to 'custom suggestion' obligates the developer to implement an instance
116
- # method on the abstractable entitty to make suggestions as
117
- # appropriate. The 'custom suggestion' source type is
118
- # intended to faciliate the generation of suggestions in a customizable way.
115
+ # method on the abstractable entitty to make suggestions as appropriate.
116
+ # The 'custom suggestion' source type is intended to faciliate the
117
+ # generation of suggestions in a customizable way. The method implemented
118
+ # by the developer should return an array of hashes, each has with 2 keys, like so
119
+ #
120
+ # [{ suggestion: 'a suggestion', explanation: 'why i made the suggestion}]
119
121
  #
122
+ # The suggestion will be presented to the user as possible answer for the
123
+ # abstraction. The explanation will be displayed to the user to explain
124
+ # how the sytem arrived at the suggestion.
120
125
  # @param [ActiveRecord::Base] about The entity to abstract. An instance of the class specified in the Abstractor::AbstractorSubject#subject_type attribute.
121
126
  # @param [Abstractor::AbstractorAbstraction] abstractor_abstraction The instance of Abstractor::AbstractorAbstraction to make suggestions against.
122
127
  # @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.
123
128
  # @return [void]
124
129
  def abstract_custom_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
125
- suggested_values = about.send(abstractor_abstraction_source.custom_method)
126
- suggested_values.each do |suggested_value|
127
- suggest(abstractor_abstraction, abstractor_abstraction_source, nil, nil, about.id, about.class.to_s, abstractor_abstraction_source.from_method, suggested_value, nil, nil, abstractor_abstraction_source.custom_method)
130
+ suggestions = about.send(abstractor_abstraction_source.custom_method)
131
+ suggestions.each do |suggestion|
132
+ suggest(abstractor_abstraction, abstractor_abstraction_source, nil, nil, about.id, about.class.to_s, abstractor_abstraction_source.from_method, suggestion[:suggestion], nil, nil, abstractor_abstraction_source.custom_method, suggestion[:explanation])
128
133
  end
129
134
  create_unknown_abstractor_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
130
135
  end
@@ -179,7 +184,7 @@ module Abstractor
179
184
  Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], object_variant)
180
185
  )
181
186
  if !reject
182
- suggest(abstractor_abstraction, abstractor_abstraction_source, object_variant.downcase, sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], abstractor_object_value, nil, nil, nil)
187
+ suggest(abstractor_abstraction, abstractor_abstraction_source, object_variant.downcase, sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], abstractor_object_value, nil, nil, nil, nil)
183
188
  end
184
189
  end
185
190
  end
@@ -206,13 +211,13 @@ module Abstractor
206
211
  match_value = "#{Regexp.escape(predicate_variant)}:\s*#{Regexp.escape(object_variant)}"
207
212
  matches = parser.scan(match_value, word_boundary: true).uniq
208
213
  matches.each do |match|
209
- suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], abstractor_object_value, nil, nil, nil)
214
+ suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], abstractor_object_value, nil, nil, nil, nil)
210
215
  end
211
216
 
212
217
  match_value = "#{Regexp.escape(predicate_variant)}#{Regexp.escape(object_variant)}"
213
218
  matches = parser.scan(match_value, word_boundary: true).uniq
214
219
  matches.each do |match|
215
- suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], abstractor_object_value, nil, nil, nil)
220
+ suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], abstractor_object_value, nil, nil, nil, nil)
216
221
  end
217
222
  end
218
223
  end
@@ -242,7 +247,7 @@ module Abstractor
242
247
  Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], object_variant)
243
248
  )
244
249
  if !reject
245
- suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], abstractor_object_value, nil, nil, nil)
250
+ suggest(abstractor_abstraction, abstractor_abstraction_source, sentence[:sentence], sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], abstractor_object_value, nil, nil, nil, nil)
246
251
  end
247
252
  end
248
253
  end
@@ -254,7 +259,7 @@ module Abstractor
254
259
  end
255
260
  end
256
261
 
257
- def suggest(abstractor_abstraction, abstractor_abstraction_source, match_value, sentence_match_value, source_id, source_type, source_method, suggested_value, unknown, not_applicable, custom_method)
262
+ def suggest(abstractor_abstraction, abstractor_abstraction_source, match_value, sentence_match_value, source_id, source_type, source_method, suggested_value, unknown, not_applicable, custom_method, custom_explanation)
258
263
  match_value.strip! unless match_value.nil?
259
264
  sentence_match_value.strip! unless sentence_match_value.nil?
260
265
  if abstractor_object_value?(suggested_value)
@@ -285,7 +290,8 @@ module Abstractor
285
290
  source_id: source_id,
286
291
  source_type: source_type,
287
292
  source_method: source_method,
288
- custom_method: custom_method
293
+ custom_method: custom_method,
294
+ custom_explanation: custom_explanation
289
295
  )
290
296
  end
291
297
  abstractor_suggestion
@@ -313,7 +319,7 @@ module Abstractor
313
319
  Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], predicate_variant)
314
320
  )
315
321
  if !reject
316
- suggest(abstractor_abstraction, abstractor_abstraction_source, predicate_variant.downcase, sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], nil, true, nil, nil)
322
+ suggest(abstractor_abstraction, abstractor_abstraction_source, predicate_variant.downcase, sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], nil, true, nil, nil, nil)
317
323
  end
318
324
  end
319
325
  end
@@ -327,7 +333,7 @@ module Abstractor
327
333
  #Create an 'unknown' suggestion based on matching nothing only if we have not made a suggstion
328
334
  abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
329
335
  if abstractor_abstraction.abstractor_suggestions(true).empty?
330
- suggest(abstractor_abstraction, abstractor_abstraction_source, nil, nil, source[:source_id], source[:source_type].to_s, source[:source_method], nil, true, nil, nil)
336
+ suggest(abstractor_abstraction, abstractor_abstraction_source, nil, nil, source[:source_id], source[:source_type].to_s, source[:source_method], nil, true, nil, nil, nil)
331
337
  end
332
338
  end
333
339
  end
@@ -9,7 +9,7 @@ module Abstractor
9
9
  base.send :belongs_to, :abstractor_abstraction_source
10
10
  base.send :belongs_to, :abstractor_suggestion
11
11
 
12
- base.send :attr_accessible, :abstractor_abstraction_source, :abstractor_abstraction_source_id, :abstractor_suggestion, :abstractor_suggestion_id, :source_id, :source_type, :source_method, :match_value, :deleted_at, :sentence_match_value, :custom_method
12
+ base.send :attr_accessible, :abstractor_abstraction_source, :abstractor_abstraction_source_id, :abstractor_suggestion, :abstractor_suggestion_id, :source_id, :source_type, :source_method, :match_value, :deleted_at, :sentence_match_value, :custom_method, :custom_explanation
13
13
  end
14
14
  end
15
15
  end
@@ -1,3 +1,3 @@
1
1
  module Abstractor
2
- VERSION = '2.0.1'
2
+ VERSION = '2.1.0'
3
3
  end
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: 2.0.1
4
+ version: 2.1.0
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: 2014-07-31 00:00:00.000000000 Z
11
+ date: 2014-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -487,6 +487,7 @@ files:
487
487
  - db/migrate/20140618140828_add_custom_method_to_abstractor_suggestion_sources.rb
488
488
  - db/migrate/20140716184049_add_dynamic_list_method_to_abstractor_subjects.rb
489
489
  - db/migrate/20140718014952_refactor_abstractor_rule_types.rb
490
+ - db/migrate/20140803205149_add_custom_explanation_to_abstractor_suggestion_sources.rb
490
491
  - db/seeds.rb
491
492
  - lib/abstractor.rb
492
493
  - lib/abstractor/abstractable.rb