abstractor 2.0.1 → 2.1.0

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