abstractor 4.0.2 → 4.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.
Files changed (28) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/abstractor/abstractor.js.coffee +13 -4
  3. data/app/models/abstractor/abstractor_section.rb +5 -0
  4. data/app/models/abstractor/abstractor_section_name_variant.rb +5 -0
  5. data/app/models/abstractor/abstractor_section_type.rb +5 -0
  6. data/app/views/abstractor/abstractor_abstraction_groups/_form.html.haml +7 -2
  7. data/app/views/abstractor/abstractor_abstraction_groups/edit.html.haml +4 -1
  8. data/app/views/abstractor/abstractor_abstractions/_fields.html.haml +9 -9
  9. data/app/views/abstractor/abstractor_abstractions/_grouped_abstractions_list.html.haml +8 -2
  10. data/app/views/abstractor/abstractor_abstractions/edit.html.haml +3 -2
  11. data/db/migrate/20141028020332_add_cardinality_to_abstractor_subject_group.rb +5 -0
  12. data/db/migrate/20141107171413_add_sectioning.rb +41 -0
  13. data/lib/abstractor/abstractable.rb +24 -5
  14. data/lib/abstractor/enum.rb +3 -0
  15. data/lib/abstractor/methods/controllers/abstractor_abstraction_groups_controller.rb +13 -4
  16. data/lib/abstractor/methods/models/abstractor_abstraction.rb +2 -0
  17. data/lib/abstractor/methods/models/abstractor_abstraction_group.rb +32 -14
  18. data/lib/abstractor/methods/models/abstractor_abstraction_group_member.rb +2 -0
  19. data/lib/abstractor/methods/models/abstractor_abstraction_source.rb +32 -2
  20. data/lib/abstractor/methods/models/abstractor_section.rb +23 -0
  21. data/lib/abstractor/methods/models/abstractor_section_name_variant.rb +14 -0
  22. data/lib/abstractor/methods/models/abstractor_section_type.rb +14 -0
  23. data/lib/abstractor/methods/models/abstractor_subject.rb +14 -13
  24. data/lib/abstractor/methods/models/abstractor_subject_group.rb +2 -0
  25. data/lib/abstractor/methods/models/abstractor_suggestion.rb +3 -2
  26. data/lib/abstractor/setup.rb +4 -0
  27. data/lib/abstractor/version.rb +1 -1
  28. metadata +10 -2
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NmFjZjhkYzhlZWVkZGI1M2Q2YWZkNmUxNTk2OGZjMDljMzc5NWNjNA==
4
+ YzNiYjAyNWRiMDJhYzQwODJkMjJkNDFjMDIzMGRiYzM4NDA1MzZlMw==
5
5
  data.tar.gz: !binary |-
6
- NzNmMzg2ZTI1Mjc3ZTU2MjI1YmEyNjE3NjVlMTRhMmU0YWIzZjI2Mw==
6
+ ZTVlMmQxZjFhM2M3Y2I2NGI5ODQ4ODE5MGVlY2M0MDAxNWZjNWYwOA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MDEwYzc1NWM5MDZjMDYwMGIxZjY1OGQ2NGU2ZGU4MzUxYmE4MTllYTkwYTg3
10
- ZWYzNjE3YTBkNTVmMzY2MjczZGZiMGMxZTQ1MzVhNjljMjA1MjQwNWIyMTVm
11
- ZTg3OGI4YWU0YjA3OGE5NzkxYjI2YjZlZTFkNGY2ZGNhYjM1YzA=
9
+ MDhkMGRhZjc3ZmNkODk3ZmFhMjYwNTY2OTQxZGVjYWUyMjAyZDczOTA4ZmY0
10
+ YzAwNDc1YWVjYmNiOGFjNDM5ODU0NmQ0YzBlMDY1YjNlMjg3ZTFmOTM3NTA1
11
+ YzE2NjEyMGYyYjdjYWJmODRmMjAyZjIxZmVjOTdhNzQ2ZjlkOTI=
12
12
  data.tar.gz: !binary |-
13
- NDMyM2FkYTAwYjQ4ZDc2MGY5NmU4OTM1MzQxNDhhNWEyZmZiZTE3MTFmOTQx
14
- NmRmOGZiNTQzOGI4YTVmMWQ2MDg5YWM4MWQyNmYzMWRjYTQxZDg1ODI0NWYx
15
- YzQ4MTlmNmQyMzI4NTI3ZThkNjk0YTQ0ODI1MDQzOTk3NjgxMGM=
13
+ MDRkN2U5MDg1YTUxNzQzM2EwYmFmNzcxYjc1MTAzMjZkNmViNDdjZDdiNGQ0
14
+ YmVkYjhkZDE0NjlmNzNmMWJjODhmMzA0NTU5NTFmODA5MzVlMzY2NzhkYTM2
15
+ OTdkNmU4NjZkNDU3MWRlYTlmOTc4YzdkOWIxNzk1N2QyY2ZjNDc=
@@ -84,18 +84,28 @@ Abstractor.AbstractionSuggestionUI = ->
84
84
  $(document).on "ajax:success", "form.edit_abstractor_suggestion", (e, data, status, xhr) ->
85
85
  $(this).closest(".abstractor_abstraction").html xhr.responseText
86
86
  return
87
-
88
87
  return
89
88
 
90
89
  Abstractor.AbstractionGroupUI = ->
90
+ validateCardinality = (group_container) ->
91
+ group_cardinality = group_container.find('input[name="abstractor_subject_group_cardinality"]')
92
+ add_group_link = group_container.find('.abstractor_group_add_link')
93
+ if (group_cardinality.length > 0) && (group_cardinality.val() == group_container.find('.abstractor_abstraction_group_member').length.toString())
94
+ $(add_group_link).hide()
95
+ else
96
+ $(add_group_link).show()
97
+
91
98
  $(document).on "ajax:success", ".abstractor_abstraction_group .abstractor_group_delete_link", (e, data, status, xhr) ->
92
- parent_div = $(this).closest(".abstractor_abstraction_group")
93
- parent_div.html xhr.responseText
99
+ subject_groups_container_div = $(this).closest(".abstractor_subject_groups_container")
100
+ abstraction_group_div = $(this).closest(".abstractor_abstraction_group")
101
+ abstraction_group_div.html xhr.responseText
102
+ validateCardinality(subject_groups_container_div)
94
103
  return
95
104
 
96
105
  $(document).on "ajax:success", ".abstractor_subject_groups_container .abstractor_group_add_link", (e, data, status, xhr) ->
97
106
  parent_div = $(this).closest(".abstractor_subject_groups_container")
98
107
  parent_div.find(".abstractor_subject_groups").append xhr.responseText
108
+ validateCardinality(parent_div)
99
109
  return
100
110
 
101
111
  $(document).on "ajax:success", ".abstractor_abstraction_group .abstractor_group_not_applicable_all_link", (e, data, status, xhr) ->
@@ -107,7 +117,6 @@ Abstractor.AbstractionGroupUI = ->
107
117
  parent_div = $(this).closest(".abstractor_abstraction_group")
108
118
  parent_div.html xhr.responseText
109
119
  return
110
-
111
120
  return
112
121
 
113
122
  new Abstractor.AbstractionUI()
@@ -0,0 +1,5 @@
1
+ module Abstractor
2
+ class AbstractorSection < ActiveRecord::Base
3
+ include Abstractor::Methods::Models::AbstractorSection
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Abstractor
2
+ class AbstractorSectionNameVariant < ActiveRecord::Base
3
+ include Abstractor::Methods::Models::AbstractorSectionNameVariant
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Abstractor
2
+ class AbstractorSectionType < ActiveRecord::Base
3
+ include Abstractor::Methods::Models::AbstractorSectionType
4
+ end
5
+ end
@@ -1,9 +1,14 @@
1
+ - namespace_type ||= @namespace_type
2
+ - namespace_id ||= @namespace_id
3
+
1
4
  - abstractor_abstraction_group ||= @abstractor_abstraction_group
2
5
 
3
6
  .abstractor_abstraction_group
4
7
  .abstractor_abstraction_group_member
5
- - abstractor_abstractions = abstractor_abstraction_group.abstractor_abstractions.not_deleted.joins(:abstractor_subject => :abstractor_subject_group_member).order('abstractor_subject_group_members.display_order')
6
- - abstractor_abstractions.each_with_index do |abstractor_abstraction, index|
8
+ - abstractor_abstractions = abstractor_abstraction_group.abstractor_abstractions.not_deleted.joins(:abstractor_subject => :abstractor_subject_group_member)
9
+ - unless namespace_type.blank? || namespace_id.blank?
10
+ - abstractor_abstractions = abstractor_abstractions.where(abstractor_subjects: { namespace_type: namespace_type, namespace_id: namespace_id})
11
+ - abstractor_abstractions.order('abstractor_subject_group_members.display_order').each_with_index do |abstractor_abstraction, index|
7
12
  %div{ class: "abstractor_abstraction #{Abstractor::Utility.dehumanize(abstractor_abstraction.abstractor_subject.abstractor_abstraction_schema.predicate)} #{'abstractor_bottom_border' if index < abstractor_abstractions.length - 1}" }
8
13
  = render :partial => 'abstractor/abstractor_abstractions/fields', :locals => {:abstractor_abstraction => abstractor_abstraction}
9
14
  .abstractor_abstraction_group_actions.abstractor_abstraction_actions
@@ -1 +1,4 @@
1
- = render 'form'
1
+ - if @abstractor_abstraction_group.errors.any?
2
+ = render 'abstractor/shared/error_messages', object: @abstractor_abstraction_group
3
+ - else
4
+ = render 'form'
@@ -27,18 +27,17 @@
27
27
  = abstractor_suggestion.display_value
28
28
  - if abstractor_suggestion.abstractor_suggestion_sources.any?
29
29
  - abstractor_suggestion.abstractor_suggestion_sources.each do |abstractor_suggestion_source|
30
- - source_about = abstractor_suggestion_source.source_type.constantize.find(abstractor_suggestion_source.source_id)
31
- - from_method = abstractor_suggestion_source.source_method
32
- - if from_method && source_about.respond_to?(from_method)
33
- - abstractable_from_column = source_about.send(from_method)
34
- - has_text_match = abstractable_from_column && abstractor_suggestion_source.sentence_match_value
35
- %span{ class: 'abstractor_abstraction_source_tooltip_img', rel: "#abstraction_text_#{abstractor_suggestion_source.id}", title: "#{source_about.class.to_s} #{from_method}"}
30
+ - source = { source_type: abstractor_suggestion_source.source_type.constantize, source_id: abstractor_suggestion_source.source_id , source_method: abstractor_suggestion_source.source_method, section_name: abstractor_suggestion_source.section_name }
31
+ - abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
32
+ - if abstractor_text
33
+ - has_text_match = abstractor_text && abstractor_suggestion_source.sentence_match_value
34
+ %span{ class: 'abstractor_abstraction_source_tooltip_img', rel: "#abstraction_text_#{abstractor_suggestion_source.id}", title: "#{abstractor_suggestion_source.source_type} #{abstractor_suggestion_source.source_method}"}
36
35
  %i{ id: "abstraction_text_link_#{abstractor_suggestion_source.id}", class: "#{'abstraction_text_link_match' if has_text_match}" }
37
36
  %div{ id: "abstraction_text_#{abstractor_suggestion_source.id}", class: 'abstractor_abstraction_source_tooltip'}
38
37
  - if has_text_match
39
- = Abstractor::UserInterface.highlight(simple_format(abstractable_from_column.clone), abstractor_suggestion_source.sentence_match_value.strip)
38
+ = Abstractor::UserInterface.highlight(simple_format(abstractor_text), abstractor_suggestion_source.sentence_match_value.strip)
40
39
  - else
41
- = simple_format(abstractable_from_column.clone)
40
+ = simple_format(abstractor_text)
42
41
  - if abstractor_suggestion_source.custom_explanation
43
42
  .custom_explanation
44
43
  %label
@@ -62,5 +61,6 @@
62
61
  %i{ id: "abstraction_text_link_#{dom_id}" }
63
62
  %br
64
63
  %div{ id: "abstraction_text_#{dom_id}", class: 'tooltip'}
65
- = simple_format(source[:source_type].find(source[:source_id]).send(source[:source_method]))
64
+ - abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
65
+ = simple_format(abstractor_text)
66
66
  .clear
@@ -1,8 +1,13 @@
1
+ - namespace_type ||= @namespace_type
2
+ - namespace_id ||= @namespace_id
3
+
1
4
  .abstractor_abstractions_grouped
2
5
  - abstractor_subject_groups = about.class.abstractor_subject_groups(namespace_type: namespace_type, namespace_id: namespace_id)
3
6
  - abstractor_subject_groups.each do |abstractor_subject_group|
4
7
  .abstractor_subject_groups_container
5
8
  %b= abstractor_subject_group.name
9
+ - if abstractor_subject_group.cardinality
10
+ = hidden_field_tag :abstractor_subject_group_cardinality, abstractor_subject_group.cardinality, id: "abstractor_subject_group_cardinality_#{abstractor_subject_group.id}"
6
11
  %fieldset
7
12
  .abstractor_abstractions_header
8
13
  .abstractor_abstraction_schema_name
@@ -18,6 +23,7 @@
18
23
  .abstractor_abstractions_body.abstractor_subject_groups
19
24
  - abstractor_abstraction_groups = about.abstractor_abstraction_groups_by_namespace(namespace_type: namespace_type, namespace_id: namespace_id, abstractor_subject_group_id: abstractor_subject_group.id)
20
25
  - abstractor_abstraction_groups.each do |abstractor_abstraction_group|
21
- = render partial: 'abstractor/abstractor_abstraction_groups/form', locals: {abstractor_abstraction_group: abstractor_abstraction_group}
22
- = link_to 'Add group', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_groups_path(about_id: about.id, about_type: about.class.name, abstractor_subject_group_id: abstractor_subject_group.id)), data: { confirm: 'Are you sure?'}, method: :post, class: 'abstractor_group_add_link', remote: true
26
+ = render partial: 'abstractor/abstractor_abstraction_groups/form', locals: {abstractor_abstraction_group: abstractor_abstraction_group, namespace_type: namespace_type, namespace_id: namespace_id}
27
+ - unless abstractor_subject_group.cardinality == 1
28
+ = link_to 'Add group', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_groups_path(about_id: about.id, about_type: about.class.name, abstractor_subject_group_id: abstractor_subject_group.id, namespace_type: namespace_type, namespace_id: namespace_id)), data: { confirm: 'Are you sure?'}, method: :post, class: 'abstractor_group_add_link', remote: true, style: "#{'display: none;' if about.abstractor_subject_group_complete?(abstractor_subject_group.id, {namespace_type: namespace_type, namespace_id: namespace_id})}"
23
29
  .clear
@@ -45,13 +45,14 @@
45
45
  - abstraction_sources = abstractor_abstraction.abstractor_subject.abstractor_abstraction_sources.select { |s| s.abstractor_abstraction_source_type.name != 'indirect' }
46
46
  - abstraction_sources.each do |abstraction_source|
47
47
  - abstraction_source.normalize_from_method_to_sources(abstractor_abstraction.about).each do |source|
48
- - if source[:source_type] && source[:source_id] && source[:source_method]
48
+ - abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
49
+ - if abstractor_text
49
50
  - dom_id = "#{abstraction_source.id}_#{source[:source_type]}_#{source[:source_id]}_#{source[:source_method]}"
50
51
  %span{ :class => 'abstractor_abstraction_source_tooltip_img', :rel =>"#abstraction_text_#{dom_id}", :title => "#{source[:source_type].to_s} #{source[:source_method]}"}
51
52
  = image_tag('abstractor/page.png', :id => "abstraction_text_link_#{dom_id}")
52
53
  %br
53
54
  %div{ :id => "abstraction_text_#{dom_id}", :class => 'tooltip'}
54
- = simple_format(source[:source_type].find(source[:source_id]).send(source[:source_method]))
55
+ = simple_format(abstractor_text)
55
56
  .abstraction_edit_abstraction_actions
56
57
  = f.submit 'Save'
57
58
  = link_to 'Cancel', abstractor_abstraction, :remote => true
@@ -0,0 +1,5 @@
1
+ class AddCardinalityToAbstractorSubjectGroup < ActiveRecord::Migration
2
+ def change
3
+ add_column :abstractor_subject_groups, :cardinality, :integer
4
+ end
5
+ end
@@ -0,0 +1,41 @@
1
+ class AddSectioning < ActiveRecord::Migration
2
+ def up
3
+ create_table :abstractor_sections do |t|
4
+ t.integer :abstractor_section_type_id
5
+ t.string :source_type
6
+ t.string :source_method
7
+ t.string :name
8
+ t.string :description
9
+ t.string :delimiter
10
+ t.string :custom_regular_expression
11
+ t.boolean :return_note_on_empty_section
12
+ t.datetime :deleted_at
13
+ t.timestamps
14
+ end
15
+
16
+ create_table :abstractor_section_types do |t|
17
+ t.string :name
18
+ t.string :regular_expression
19
+ t.datetime :deleted_at
20
+ t.timestamps
21
+ end
22
+
23
+ create_table :abstractor_section_name_variants do |t|
24
+ t.integer :abstractor_section_id
25
+ t.string :name
26
+ t.datetime :deleted_at
27
+ t.timestamps
28
+ end
29
+
30
+ add_column :abstractor_abstraction_sources, :section_name, :string
31
+ add_column :abstractor_suggestion_sources, :section_name, :string
32
+ end
33
+
34
+ def down
35
+ drop_table :abstractor_sections
36
+ drop_table :abstractor_section_types
37
+ drop_table :abstractor_section_name_variants
38
+ remove_column :abstractor_abstraction_sources, :section_name
39
+ remove_column :abstractor_suggestion_sources, :section_name
40
+ end
41
+ end
@@ -76,7 +76,7 @@ module Abstractor
76
76
  end
77
77
 
78
78
  def detect_abstractor_abstraction(abstractor_subject)
79
- abstractor_abstractions(true).not_deleted.detect { |abstractor_abstraction| abstractor_abstraction.abstractor_subject == abstractor_subject }
79
+ abstractor_abstractions(true).not_deleted.detect { |abstractor_abstraction| abstractor_abstraction.abstractor_subject_id == abstractor_subject.id }
80
80
  end
81
81
 
82
82
  def find_or_create_abstractor_abstraction(abstractor_abstraction_schema, abstractor_subject)
@@ -84,25 +84,44 @@ module Abstractor
84
84
  else
85
85
  abstractor_abstraction = Abstractor::AbstractorAbstraction.create!(abstractor_subject: abstractor_subject, about: self)
86
86
  if abstractor_subject.groupable?
87
- abstractor_abstraction_group = find_or_create_abstractor_abstraction_group(abstractor_subject.abstractor_subject_group)
87
+ abstractor_abstraction_group = find_or_initialize_abstractor_abstraction_group(abstractor_subject.abstractor_subject_group)
88
88
  abstractor_abstraction_group.abstractor_abstractions << abstractor_abstraction
89
+ abstractor_abstraction_group.save!
89
90
  end
90
91
  end
91
92
  abstractor_abstraction
92
93
  end
93
94
 
94
95
  def detect_abstractor_abstraction_group(abstractor_subject_group)
95
- abstractor_abstraction_groups(true).detect { |abstractor_abstraction_group| abstractor_abstraction_group.abstractor_subject_group == abstractor_subject_group }
96
+ abstractor_abstraction_groups(true).detect { |abstractor_abstraction_group| abstractor_abstraction_group.abstractor_subject_group_id == abstractor_subject_group.id }
96
97
  end
97
98
 
98
- def find_or_create_abstractor_abstraction_group(abstractor_subject_group)
99
+ def find_or_initialize_abstractor_abstraction_group(abstractor_subject_group)
99
100
  if abstractor_abstraction_group = detect_abstractor_abstraction_group(abstractor_subject_group)
100
101
  else
101
- abstractor_abstraction_group = Abstractor::AbstractorAbstractionGroup.create(abstractor_subject_group: abstractor_subject_group, about: self)
102
+ abstractor_abstraction_group = Abstractor::AbstractorAbstractionGroup.new(abstractor_subject_group: abstractor_subject_group, about: self)
102
103
  end
103
104
  abstractor_abstraction_group
104
105
  end
105
106
 
107
+ ##
108
+ # Determines if provided abstractor_subject_group reached number of abstractor_abstraction_groups defined by abstractor_subject_group cardinality
109
+ #
110
+ # @param [Integer] abstractor_subject_group_id the id of abstractor_subject_group of interest.
111
+ # @option options [String] :namespace_type the type parameter of the namespace.
112
+ # @option options [Integer] :namespace_id the instance parameter of the namespace.
113
+ # @return [boolean]
114
+ def abstractor_subject_group_complete?(abstractor_subject_group_id, options = {})
115
+ abstractor_subject_group = Abstractor::AbstractorSubjectGroup.find(abstractor_subject_group_id)
116
+ if abstractor_subject_group.cardinality.blank?
117
+ false
118
+ else
119
+ options = { namespace_type: nil, namespace_id: nil, abstractor_subject_group_id: abstractor_subject_group_id }.merge(options)
120
+ abstractor_abstraction_groups = abstractor_abstraction_groups_by_namespace(options)
121
+ abstractor_abstraction_groups.length == abstractor_subject_group.cardinality
122
+ end
123
+ end
124
+
106
125
  ##
107
126
  # Returns all abstraction for the abstractable entity by abstractor_abstraction_status:
108
127
  #
@@ -7,5 +7,8 @@ module Abstractor
7
7
  ABSTRACTION_STATUS_NEEDS_REVIEW = 'needs review'
8
8
  ABSTRACTION_STATUS_REVIEWED = 'reviewed'
9
9
  ABSTRACTION_STATUSES = [ABSTRACTION_STATUS_NEEDS_REVIEW, ABSTRACTION_STATUS_REVIEWED]
10
+
11
+ ABSTRACTOR_SECTION_TYPE_CUSTOM = 'custom'
12
+ ABSTRACTOR_SECTION_TYPE_NAME_VALUE = 'name/value'
10
13
  end
11
14
  end
@@ -8,16 +8,25 @@ module Abstractor
8
8
  end
9
9
 
10
10
  def create
11
- @abstractor_abstraction_group = Abstractor::AbstractorAbstractionGroup.create(abstractor_subject_group_id: params[:abstractor_subject_group_id], about_type: params[:about_type], about_id: params[:about_id])
12
- @abstractor_abstraction_group.abstractor_subject_group.abstractor_subjects.each do |abstractor_subject|
11
+ @abstractor_abstraction_group = Abstractor::AbstractorAbstractionGroup.new(abstractor_subject_group_id: params[:abstractor_subject_group_id], about_type: params[:about_type], about_id: params[:about_id])
12
+
13
+ abstractor_subjects = @abstractor_abstraction_group.abstractor_subject_group.abstractor_subjects
14
+ unless params[:namespace_type].blank? || params[:namespace_id].blank?
15
+ @namespace_id = params[:namespace_id]
16
+ @namespace_type = params[:namespace_type]
17
+ abstractor_subjects = abstractor_subjects.where(namespace_type: @namespace_type, namespace_id: @namespace_id)
18
+ end
19
+
20
+ abstractor_subjects.each do |abstractor_subject|
13
21
  abstraction = abstractor_subject.abstractor_abstractions.build(about_id: params[:about_id], about_type: params[:about_type])
14
- abstraction.build_abstractor_abstraction_group_member(abstractor_abstraction_group: @abstractor_abstraction_group)
15
22
  abstraction.abstractor_subject.abstractor_abstraction_sources.select { |s| s.abstractor_abstraction_source_type.name == 'indirect' }.each do |abstractor_abstraction_source|
16
23
  source = abstractor_subject.subject_type.constantize.find(params[:about_id]).send(abstractor_abstraction_source.from_method)
17
24
  abstraction.abstractor_indirect_sources.build(abstractor_abstraction_source: abstractor_abstraction_source, source_type: source[:source_type], source_method: source[:source_method])
25
+
18
26
  end
19
- abstraction.save!
27
+ @abstractor_abstraction_group.abstractor_abstractions << abstraction
20
28
  end
29
+ @abstractor_abstraction_group.save!
21
30
 
22
31
  respond_to do |format|
23
32
  format.html { render action: "edit", layout: false }
@@ -22,6 +22,8 @@ module Abstractor
22
22
 
23
23
  base.send :belongs_to, :about, polymorphic: true
24
24
 
25
+ base.send :validates_associated, :abstractor_subject
26
+
25
27
  # base.send :attr_accessible, :about, :abstractor_subject, :abstractor_subject_id, :value, :about_type, :about_id, :unknown, :not_applicable, :deleted_at, :abstractor_indirect_sources_attributes
26
28
 
27
29
  # Hooks
@@ -15,25 +15,43 @@ module Abstractor
15
15
  # base.send :attr_accessible, :abstractor_subject_group, :abstractor_subject_group_id, :deleted_at, :about, :about_type, :about_id
16
16
 
17
17
  # Hooks
18
+ base.send :validate, :validate_subject_group_cardinality
19
+ base.send :validate, :must_have_members
20
+
18
21
  base.send :after_commit, :update_abstractor_abstraction_group_members, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
19
- end
20
22
 
21
- ##
22
- # Determines if the group can be removed.
23
- #
24
- # @return [Boolean]
25
- def removable?
26
- abstractor_abstractions.map(&:abstractor_suggestions).flatten.empty?
23
+ base.send(:include, InstanceMethods)
27
24
  end
28
25
 
29
- private
30
- def update_abstractor_abstraction_group_members
31
- return unless deleted?
32
- abstractor_abstraction_group_members.each do |gm|
33
- gm.soft_delete!
34
- gm.abstractor_abstraction.soft_delete!
35
- end
26
+ module InstanceMethods
27
+ ##
28
+ # Determines if the group can be removed.
29
+ #
30
+ # @return [Boolean]
31
+ def removable?
32
+ abstractor_abstractions.map(&:abstractor_suggestions).flatten.empty?
36
33
  end
34
+
35
+ private
36
+ def update_abstractor_abstraction_group_members
37
+ return unless deleted?
38
+ abstractor_abstraction_group_members.each do |gm|
39
+ gm.soft_delete!
40
+ gm.abstractor_abstraction.soft_delete!
41
+ end
42
+ end
43
+
44
+ def must_have_members
45
+ if self.abstractor_abstraction_group_members.empty? || self.abstractor_abstraction_group_members.all? {|abstractor_abstraction_group_member| abstractor_abstraction_group_member.marked_for_destruction? }
46
+ errors.add(:base, 'Must have at least one abstractor_abstraction_group_member')
47
+ end
48
+ end
49
+
50
+ def validate_subject_group_cardinality
51
+ return if self.abstractor_subject_group.cardinality.blank? || self.persisted?
52
+ errors.add(:base,"Subject group reached maximum number of abstraction groups (#{abstractor_subject_group.cardinality})") if self.about.abstractor_subject_group_complete?(self.abstractor_subject_group_id)
53
+ end
54
+ end
37
55
  end
38
56
  end
39
57
  end
@@ -9,6 +9,8 @@ module Abstractor
9
9
  base.send :belongs_to, :abstractor_abstraction_group
10
10
  base.send :belongs_to, :abstractor_abstraction
11
11
 
12
+ base.send :validates_associated, :abstractor_abstraction
13
+
12
14
  # base.send :attr_accessible, :abstractor_abstraction_group, :abstractor_abstraction_group_id, :abstractor_abstraction, :abstractor_abstraction_id, :deleted_at
13
15
  end
14
16
  end
@@ -9,11 +9,41 @@ module Abstractor
9
9
  base.send :belongs_to, :abstractor_subject
10
10
  base.send :belongs_to, :abstractor_rule_type
11
11
  base.send :belongs_to, :abstractor_abstraction_source_type
12
+ base.send :belongs_to, :abstractor_abstraction_source_section_type
12
13
  base.send :has_many, :abstractor_suggestion_sources
13
14
  base.send :has_many, :abstractor_abstractions, :through => :abstractor_suggestion_sources
14
15
  base.send :has_many, :abstractor_indirect_sources
16
+ base.send :has_many, :abstractor_abstraction_source_section_name_variants
15
17
 
16
- # base.send :attr_accessible, :abstractor_subject, :abstractor_subject_id, :deleted_at, :from_method, :custom_method, :abstractor_rule_type, :abstractor_rule_type_id, :abstractor_abstraction_source_type, :abstractor_abstraction_source_type_id
18
+ def base.abstractor_text(source)
19
+ text = source[:source_type].find(source[:source_id]).send(source[:source_method])
20
+ if !source[:section_name].blank?
21
+ abstractor_section = Abstractor::AbstractorSection.where(source_type: source[:source_type], source_method: source[:source_method], name: source[:section_name]).first
22
+ if text =~ prepare_section_regular_expression(abstractor_section)
23
+ text = $2
24
+ else
25
+ if abstractor_section.return_note_on_empty_section
26
+ text = text
27
+ else
28
+ text = ''
29
+ end
30
+ end
31
+ end
32
+
33
+ text
34
+ end
35
+
36
+ def base.prepare_section_regular_expression(abstractor_section)
37
+ regular_expression = nil
38
+ if abstractor_section.abstractor_section_type.name == Abstractor::Enum::ABSTRACTOR_SECTION_TYPE_CUSTOM
39
+ regular_expression = abstractor_section.custom_regular_expression
40
+ else
41
+ regular_expression = abstractor_section.abstractor_section_type.regular_expression
42
+ end
43
+ regular_expression.gsub!('section_name_variants', abstractor_section.prepare_section_name_variants)
44
+ regular_expression.gsub!('delimiter', abstractor_section.delimiter)
45
+ Regexp.new(regular_expression, Regexp::IGNORECASE)
46
+ end
17
47
  end
18
48
 
19
49
  def normalize_from_method_to_sources(about)
@@ -21,7 +51,7 @@ module Abstractor
21
51
  fm = nil
22
52
  fm = about.send(from_method) unless from_method.blank?
23
53
  if fm.is_a?(String) || fm.nil?
24
- sources = [{ source_type: about.class , source_id: about.id , source_method: from_method }]
54
+ sources = [{ source_type: about.class , source_id: about.id , source_method: from_method, section_name: section_name }]
25
55
  else
26
56
  sources = fm
27
57
  end
@@ -0,0 +1,23 @@
1
+ module Abstractor
2
+ module Methods
3
+ module Models
4
+ module AbstractorSection
5
+ def self.included(base)
6
+ base.send :include, SoftDelete
7
+
8
+ # Associations
9
+ base.send :belongs_to, :abstractor_section_type
10
+ base.send :has_many, :abstractor_section_name_variants
11
+ end
12
+
13
+ def prepare_section_name_variants
14
+ section_name_variants.join('|')
15
+ end
16
+
17
+ def section_name_variants
18
+ [name].concat(abstractor_section_name_variants.map(&:name))
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module Abstractor
2
+ module Methods
3
+ module Models
4
+ module AbstractorSectionNameVariant
5
+ def self.included(base)
6
+ base.send :include, SoftDelete
7
+
8
+ # Associations
9
+ base.send :belongs_to, :abstractor_section
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Abstractor
2
+ module Methods
3
+ module Models
4
+ module AbstractorSectionType
5
+ def self.included(base)
6
+ base.send :include, SoftDelete
7
+
8
+ # Associations
9
+ base.send :has_many, :abstractor_sections
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -129,7 +129,7 @@ module Abstractor
129
129
  def abstract_custom_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
130
130
  suggestions = about.send(abstractor_abstraction_source.custom_method)
131
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])
132
+ suggest(abstractor_abstraction, abstractor_abstraction_source, nil, nil, about.id, about.class.to_s, abstractor_abstraction_source.from_method, abstractor_abstraction_source.section_name, suggestion[:suggestion], nil, nil, abstractor_abstraction_source.custom_method, suggestion[:explanation])
133
133
  end
134
134
  create_unknown_abstractor_suggestion(about, abstractor_abstraction, abstractor_abstraction_source)
135
135
  end
@@ -145,7 +145,7 @@ module Abstractor
145
145
 
146
146
  def abstract_sentential_value(about, abstractor_abstraction, abstractor_abstraction_source)
147
147
  abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
148
- abstractor_text = source[:source_type].find(source[:source_id]).send(source[:source_method])
148
+ abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
149
149
  abstractor_object_value_ids = abstractor_abstraction_schema.abstractor_object_values.map(&:id)
150
150
 
151
151
  abstractor_object_values = []
@@ -187,7 +187,7 @@ module Abstractor
187
187
  Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], object_variant)
188
188
  )
189
189
  if !reject
190
- 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)
190
+ suggest(abstractor_abstraction, abstractor_abstraction_source, object_variant.downcase, sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], abstractor_object_value, nil, nil, nil, nil)
191
191
  end
192
192
  end
193
193
  end
@@ -206,7 +206,7 @@ module Abstractor
206
206
 
207
207
  def abstract_canonical_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
208
208
  abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
209
- abstractor_text = source[:source_type].find(source[:source_id]).send(source[:source_method])
209
+ abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
210
210
  parser = Abstractor::Parser.new(abstractor_text)
211
211
  abstractor_abstraction_schema.predicate_variants.each do |predicate_variant|
212
212
  abstractor_abstraction_schema.abstractor_object_values.each do |abstractor_object_value|
@@ -214,13 +214,13 @@ module Abstractor
214
214
  match_value = "#{Regexp.escape(predicate_variant)}:\s*#{Regexp.escape(object_variant)}"
215
215
  matches = parser.scan(match_value, word_boundary: true).uniq
216
216
  matches.each do |match|
217
- 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)
217
+ 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)
218
218
  end
219
219
 
220
220
  match_value = "#{Regexp.escape(predicate_variant)}#{Regexp.escape(object_variant)}"
221
221
  matches = parser.scan(match_value, word_boundary: true).uniq
222
222
  matches.each do |match|
223
- 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)
223
+ suggest(abstractor_abstraction, abstractor_abstraction_source, match, match, source[:source_id], source[:source_type].to_s, source[:source_method], source[:seciton_name], abstractor_object_value, nil, nil, nil, nil)
224
224
  end
225
225
  end
226
226
  end
@@ -230,7 +230,7 @@ module Abstractor
230
230
 
231
231
  def abstract_sentential_name_value(about, abstractor_abstraction, abstractor_abstraction_source)
232
232
  abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
233
- abstractor_text = source[:source_type].find(source[:source_id]).send(source[:source_method])
233
+ abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
234
234
  parser = Abstractor::Parser.new(abstractor_text)
235
235
  abstractor_abstraction_schema.predicate_variants.each do |predicate_variant|
236
236
  ranges = parser.range_all(Regexp.escape(predicate_variant))
@@ -250,7 +250,7 @@ module Abstractor
250
250
  Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], object_variant)
251
251
  )
252
252
  if !reject
253
- 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)
253
+ 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)
254
254
  end
255
255
  end
256
256
  end
@@ -262,7 +262,7 @@ module Abstractor
262
262
  end
263
263
  end
264
264
 
265
- 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)
265
+ def suggest(abstractor_abstraction, abstractor_abstraction_source, match_value, sentence_match_value, source_id, source_type, source_method, section_name, suggested_value, unknown, not_applicable, custom_method, custom_explanation)
266
266
  match_value.strip! unless match_value.nil?
267
267
  sentence_match_value.strip! unless sentence_match_value.nil?
268
268
  if abstractor_object_value?(suggested_value)
@@ -283,7 +283,7 @@ module Abstractor
283
283
  abstractor_suggestion.abstractor_suggestion_object_value = Abstractor::AbstractorSuggestionObjectValue.new(abstractor_object_value: abstractor_object_value) if abstractor_object_value
284
284
  end
285
285
 
286
- abstractor_suggestion_source = abstractor_suggestion.detect_abstractor_suggestion_source(abstractor_abstraction_source, sentence_match_value, source_id, source_type, source_method)
286
+ abstractor_suggestion_source = abstractor_suggestion.detect_abstractor_suggestion_source(abstractor_abstraction_source, sentence_match_value, source_id, source_type, source_method, section_name)
287
287
  if !abstractor_suggestion_source
288
288
  Abstractor::AbstractorSuggestionSource.create(
289
289
  abstractor_abstraction_source: abstractor_abstraction_source,
@@ -293,6 +293,7 @@ module Abstractor
293
293
  source_id: source_id,
294
294
  source_type: source_type,
295
295
  source_method: source_method,
296
+ section_name: section_name,
296
297
  custom_method: custom_method,
297
298
  custom_explanation: custom_explanation
298
299
  )
@@ -306,7 +307,7 @@ module Abstractor
306
307
 
307
308
  def create_unknown_abstractor_suggestion_name_only(about, abstractor_abstraction, abstractor_abstraction_source)
308
309
  abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
309
- abstractor_text = source[:source_type].find(source[:source_id]).send(source[:source_method])
310
+ abstractor_text = Abstractor::AbstractorAbstractionSource.abstractor_text(source)
310
311
  parser = Abstractor::Parser.new(abstractor_text)
311
312
  #Create an 'unknown' suggestion based on match name only if we have not made a suggstion
312
313
  if abstractor_abstraction.abstractor_suggestions(true).empty?
@@ -322,7 +323,7 @@ module Abstractor
322
323
  Abstractor::NegationDetection.manual_negated_match_value?(sentence[:sentence], predicate_variant)
323
324
  )
324
325
  if !reject
325
- 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)
326
+ suggest(abstractor_abstraction, abstractor_abstraction_source, predicate_variant.downcase, sentence[:sentence], source[:source_id], source[:source_type].to_s, source[:source_method], source[:section_name], nil, true, nil, nil, nil)
326
327
  end
327
328
  end
328
329
  end
@@ -336,7 +337,7 @@ module Abstractor
336
337
  #Create an 'unknown' suggestion based on matching nothing only if we have not made a suggstion
337
338
  abstractor_abstraction_source.normalize_from_method_to_sources(about).each do |source|
338
339
  if abstractor_abstraction.abstractor_suggestions(true).select { |abstractor_suggestion| abstractor_suggestion.unknown != true }.empty?
339
- suggest(abstractor_abstraction, abstractor_abstraction_source, nil, nil, source[:source_id], source[:source_type].to_s, source[:source_method], nil, true, nil, nil, nil)
340
+ 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)
340
341
  end
341
342
  end
342
343
  end
@@ -12,6 +12,8 @@ module Abstractor
12
12
  base.send :has_many, :abstractor_abstractions, :through => :abstractor_abstraction_groups
13
13
 
14
14
  # base.send :attr_accessible, :deleted_at, :name
15
+ # Validations
16
+ base.send :validates, :cardinality, numericality: { only_integer: true, greater_than: 0 }, unless: Proc.new { |a| a.cardinality.blank? }
15
17
  end
16
18
  end
17
19
  end
@@ -74,13 +74,14 @@ module Abstractor
74
74
  abstractor_abstraction.abstractor_suggestions.where('id != ?', id)
75
75
  end
76
76
 
77
- def detect_abstractor_suggestion_source(abstractor_abstraction_source, sentence_match_value, source_id, source_type, source_method)
77
+ def detect_abstractor_suggestion_source(abstractor_abstraction_source, sentence_match_value, source_id, source_type, source_method, section_name)
78
78
  abstractor_suggestion_source = abstractor_suggestion_sources.detect do |abstractor_suggestion_source|
79
79
  abstractor_suggestion_source.abstractor_abstraction_source == abstractor_abstraction_source &&
80
80
  abstractor_suggestion_source.sentence_match_value == sentence_match_value &&
81
81
  abstractor_suggestion_source.source_id == source_id &&
82
82
  abstractor_suggestion_source.source_type == source_type &&
83
- abstractor_suggestion_source.source_method == source_method
83
+ abstractor_suggestion_source.source_method == source_method &&
84
+ abstractor_suggestion_source.section_name == section_name
84
85
  end
85
86
  end
86
87
  end
@@ -28,6 +28,10 @@ module Abstractor
28
28
  Abstractor::AbstractorAbstractionSourceType.where(name: 'nlp suggestion').first_or_create
29
29
  Abstractor::AbstractorAbstractionSourceType.where(name: 'custom suggestion').first_or_create
30
30
  Abstractor::AbstractorAbstractionSourceType.where(name: 'indirect').first_or_create
31
+
32
+ puts 'Setting up Abstractor::AbstractorSectionType'
33
+ Abstractor::AbstractorSectionType.where(name: Abstractor::Enum::ABSTRACTOR_SECTION_TYPE_CUSTOM).first_or_create
34
+ Abstractor::AbstractorSectionType.where(name: Abstractor::Enum::ABSTRACTOR_SECTION_TYPE_NAME_VALUE, regular_expression: "(?<=^|[\r\n])(section_name_variants)[\s]*delimiter([^\r\n]*(?:[\r\n]+(?![A-Z].*delimiter).*)*)").first_or_create
31
35
  end
32
36
  end
33
37
  end
@@ -1,3 +1,3 @@
1
1
  module Abstractor
2
- VERSION = '4.0.2'
2
+ VERSION = '4.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: 4.0.2
4
+ version: 4.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-10-24 00:00:00.000000000 Z
11
+ date: 2014-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -465,6 +465,9 @@ files:
465
465
  - app/models/abstractor/abstractor_object_value_variant.rb
466
466
  - app/models/abstractor/abstractor_relation_type.rb
467
467
  - app/models/abstractor/abstractor_rule_type.rb
468
+ - app/models/abstractor/abstractor_section.rb
469
+ - app/models/abstractor/abstractor_section_name_variant.rb
470
+ - app/models/abstractor/abstractor_section_type.rb
468
471
  - app/models/abstractor/abstractor_subject.rb
469
472
  - app/models/abstractor/abstractor_subject_group.rb
470
473
  - app/models/abstractor/abstractor_subject_group_member.rb
@@ -512,6 +515,8 @@ files:
512
515
  - db/migrate/20140718014952_refactor_abstractor_rule_types.rb
513
516
  - db/migrate/20140803205149_add_custom_explanation_to_abstractor_suggestion_sources.rb
514
517
  - db/migrate/20140816005228_add_namespace_to_abstractor_subjects.rb
518
+ - db/migrate/20141028020332_add_cardinality_to_abstractor_subject_group.rb
519
+ - db/migrate/20141107171413_add_sectioning.rb
515
520
  - db/seeds.rb
516
521
  - lib/abstractor.rb
517
522
  - lib/abstractor/abstractable.rb
@@ -536,6 +541,9 @@ files:
536
541
  - lib/abstractor/methods/models/abstractor_object_value_variant.rb
537
542
  - lib/abstractor/methods/models/abstractor_relation_type.rb
538
543
  - lib/abstractor/methods/models/abstractor_rule_type.rb
544
+ - lib/abstractor/methods/models/abstractor_section.rb
545
+ - lib/abstractor/methods/models/abstractor_section_name_variant.rb
546
+ - lib/abstractor/methods/models/abstractor_section_type.rb
539
547
  - lib/abstractor/methods/models/abstractor_subject.rb
540
548
  - lib/abstractor/methods/models/abstractor_subject_group.rb
541
549
  - lib/abstractor/methods/models/abstractor_subject_group_member.rb