abstractor 4.0.2 → 4.1.0

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