mention_system 0.0.6

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 (68) hide show
  1. checksums.yaml +7 -0
  2. data/.empty +0 -0
  3. data/.gitignore +15 -0
  4. data/.keep +0 -0
  5. data/.rspec +2 -0
  6. data/.ruby-gemset +1 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +23 -0
  9. data/Appraisals +7 -0
  10. data/Gemfile +4 -0
  11. data/LICENSE.txt +22 -0
  12. data/README.md +170 -0
  13. data/Rakefile +8 -0
  14. data/gemfiles/.empty +0 -0
  15. data/gemfiles/.gitignore +0 -0
  16. data/gemfiles/.keep +0 -0
  17. data/gemfiles/rails4.1.gemfile +7 -0
  18. data/gemfiles/rails4.2.gemfile +7 -0
  19. data/lib/.empty +0 -0
  20. data/lib/.gitignore +0 -0
  21. data/lib/.keep +0 -0
  22. data/lib/generators/.empty +0 -0
  23. data/lib/generators/.gitignore +0 -0
  24. data/lib/generators/.keep +0 -0
  25. data/lib/generators/mention_system/.empty +0 -0
  26. data/lib/generators/mention_system/.gitignore +0 -0
  27. data/lib/generators/mention_system/.keep +0 -0
  28. data/lib/generators/mention_system/mention_system_generator.rb +46 -0
  29. data/lib/generators/mention_system/templates/.empty +0 -0
  30. data/lib/generators/mention_system/templates/.gitignore +0 -0
  31. data/lib/generators/mention_system/templates/.keep +0 -0
  32. data/lib/generators/mention_system/templates/migration.rb +47 -0
  33. data/lib/mention_system.rb +46 -0
  34. data/lib/mention_system/.empty +0 -0
  35. data/lib/mention_system/.gitignore +0 -0
  36. data/lib/mention_system/.keep +0 -0
  37. data/lib/mention_system/mention.rb +155 -0
  38. data/lib/mention_system/mention_processor.rb +141 -0
  39. data/lib/mention_system/mentionee.rb +58 -0
  40. data/lib/mention_system/mentioner.rb +88 -0
  41. data/lib/mention_system/version.rb +12 -0
  42. data/mention_system.gemspec +31 -0
  43. data/spec/.empty +0 -0
  44. data/spec/.gitignore +0 -0
  45. data/spec/.keep +0 -0
  46. data/spec/db/.empty +0 -0
  47. data/spec/db/.gitignore +0 -0
  48. data/spec/db/.keep +0 -0
  49. data/spec/db/migrate/.empty +0 -0
  50. data/spec/db/migrate/.gitignore +0 -0
  51. data/spec/db/migrate/.keep +0 -0
  52. data/spec/db/migrate/20140926000000_create_mentions.rb +47 -0
  53. data/spec/db/migrate/20140926000005_create_dummy_mentioners.rb +22 -0
  54. data/spec/db/migrate/20140926000010_create_dummy_mentionees.rb +22 -0
  55. data/spec/mention_system/.empty +0 -0
  56. data/spec/mention_system/.gitignore +0 -0
  57. data/spec/mention_system/.keep +0 -0
  58. data/spec/mention_system/mention_processor_spec.rb +155 -0
  59. data/spec/mention_system/mention_spec.rb +177 -0
  60. data/spec/mention_system/mentionee_spec.rb +69 -0
  61. data/spec/mention_system/mentioner_spec.rb +96 -0
  62. data/spec/spec_helper.rb +116 -0
  63. data/spec/support/.empty +0 -0
  64. data/spec/support/.gitignore +0 -0
  65. data/spec/support/.keep +0 -0
  66. data/spec/support/active_record.rb +12 -0
  67. data/spec/support/shoulda_matchers.rb +2 -0
  68. metadata +240 -0
File without changes
File without changes
File without changes
@@ -0,0 +1,155 @@
1
+ ###
2
+ # MentionSystem module
3
+ #
4
+ # This module defines common behavior in mention system
5
+ ###
6
+ module MentionSystem
7
+ ###
8
+ # Mention class
9
+ #
10
+ # This class defines the mention model in mention system
11
+ ###
12
+ class Mention < ActiveRecord::Base
13
+ ###
14
+ # Belongs to mentionee association configuration
15
+ ###
16
+ belongs_to :mentionee, polymorphic: :true
17
+
18
+ ###
19
+ # Belongs to mentioner association configuration
20
+ ###
21
+ belongs_to :mentioner, polymorphic: :true
22
+
23
+ ###
24
+ # Creates a {Mention} relationship between a {Mentioner} object and a {Mentionee} object
25
+ #
26
+ # @param [Mentioner] mentioner - the {Mentioner} of the relationship
27
+ # @param [Mentionee] mentionee - the {Mentionee} of the relationship
28
+ # @return [Boolean]
29
+ ###
30
+ def self.mention(mentioner, mentionee)
31
+ validate_mentionee(mentionee)
32
+ validate_mentioner(mentioner)
33
+
34
+ if mentions?(mentioner, mentionee)
35
+ false
36
+ else
37
+ mention = scope_by_mentioner(mentioner).scope_by_mentionee(mentionee).build
38
+ mention.save
39
+ true
40
+ end
41
+ end
42
+
43
+ ###
44
+ # Destroys a {Mention} relationship between a {Mentioner} object and a {Mentionee} object
45
+ #
46
+ # @param [Mentioner] mentioner - the {Mentioner} of the relationship
47
+ # @param [Mentionee] mentionee - the {Mentionee} of the relationship
48
+ # @return [Boolean]
49
+ ###
50
+ def self.unmention(mentioner, mentionee)
51
+ validate_mentionee(mentionee)
52
+ validate_mentioner(mentioner)
53
+
54
+ if mentions?(mentioner, mentionee)
55
+ mention = scope_by_mentioner(mentioner).scope_by_mentionee(mentionee).take
56
+ mention.destroy
57
+ true
58
+ else
59
+ false
60
+ end
61
+ end
62
+
63
+ ###
64
+ # Toggles a {Mention} relationship between a {Mentioner} object and a {Mentionee} object
65
+ #
66
+ # @param [Mentioner] mentioner - the {Mentioner} of the relationship
67
+ # @param [Mentionee] mentionee - the {Mentionee} of the relationship
68
+ # @return [Boolean]
69
+ ###
70
+ def self.toggle_mention(mentioner, mentionee)
71
+ validate_mentionee(mentionee)
72
+ validate_mentioner(mentioner)
73
+
74
+ if mentions?(mentioner, mentionee)
75
+ unmention(mentioner, mentionee)
76
+ else
77
+ mention(mentioner, mentionee)
78
+ end
79
+ end
80
+
81
+ ###
82
+ # Specifies if a {Mentioner} object mentions a {Mentionee} object
83
+ #
84
+ # @param [Mentioner] mentioner - the {Mentioner} object to test against
85
+ # @param [Mentionee] mentionee - the {Mentionee} object to test against
86
+ # @return [Boolean]
87
+ ###
88
+ def self.mentions?(mentioner, mentionee)
89
+ validate_mentionee(mentionee)
90
+ validate_mentioner(mentioner)
91
+
92
+ scope_by_mentioner(mentioner).scope_by_mentionee(mentionee).exists?
93
+ end
94
+
95
+ ###
96
+ # Retrieves a scope of {Mention} objects filtered by a {Mentionee} object
97
+ #
98
+ # @param [Mentionee] mentionee - the {Mentionee} to filter
99
+ # @return [ActiveRecord::Relation]
100
+ ###
101
+ def self.scope_by_mentionee(mentionee)
102
+ where(mentionee: mentionee)
103
+ end
104
+
105
+ ###
106
+ # Retrieves a scope of {Mention} objects filtered by a {Mentionee} type
107
+ #
108
+ # @param [Class] klass - the {Class} to filter
109
+ # @return [ActiveRecord::Relation]
110
+ ###
111
+ def self.scope_by_mentionee_type(klass)
112
+ where(mentionee_type: klass.to_s.classify)
113
+ end
114
+
115
+ ###
116
+ # Retrieves a scope of {Mention} objects filtered by a {Mentioner} object
117
+ #
118
+ # @param [Mentioner] mentioner - the {Mentioner} to filter
119
+ # @return [ActiveRecord::Relation]
120
+ ###
121
+ def self.scope_by_mentioner(mentioner)
122
+ where(mentioner: mentioner)
123
+ end
124
+
125
+ ###
126
+ # Retrieves a scope of {Mention} objects filtered by a {Mentioner} type
127
+ #
128
+ # @param [Class] klass - the {Class} to filter
129
+ # @return [ActiveRecord::Relation]
130
+ ###
131
+ def self.scope_by_mentioner_type(klass)
132
+ where(mentioner_type: klass.to_s.classify)
133
+ end
134
+
135
+ private
136
+ ###
137
+ # Validates a mentionee object
138
+ #
139
+ # @raise [ArgumentError] if the mentionee object is invalid
140
+ ###
141
+ def self.validate_mentionee(mentionee)
142
+ raise ArgumentError.new unless mentionee.respond_to?(:is_mentionee?) && mentionee.is_mentionee?
143
+ end
144
+
145
+ ###
146
+ # Validates a mentioner object
147
+ #
148
+ # @raise [ArgumentError] if the mentioner object is invalid
149
+ ###
150
+ def self.validate_mentioner(mentioner)
151
+ raise ArgumentError.new unless mentioner.respond_to?(:is_mentioner?) && mentioner.is_mentioner?
152
+ end
153
+ end
154
+ end
155
+
@@ -0,0 +1,141 @@
1
+ ###
2
+ # MentionSystem module
3
+ #
4
+ # This module defines common behavior in mention system
5
+ ###
6
+ module MentionSystem
7
+ ###
8
+ # MentionProcessor class
9
+ #
10
+ # This class defines mention processor behavior in mention system
11
+ ###
12
+ class MentionProcessor
13
+ ###
14
+ # Constructor of the MentionProcessor class
15
+ ###
16
+ def initialize
17
+ @callbacks = { after: [], before: [] }
18
+ end
19
+
20
+ ###
21
+ # Adds an after callback
22
+ #
23
+ # @param [Proc] callback - the callback to add
24
+ ###
25
+ def add_after_callback(callback)
26
+ @callbacks[:after].push(callback)
27
+ end
28
+
29
+ ###
30
+ # Adds a before callback
31
+ #
32
+ # @param [Proc] callback - the callback to add
33
+ ###
34
+ def add_before_callback(callback)
35
+ @callbacks[:before].push(callback)
36
+ end
37
+
38
+ ###
39
+ # Extract handles from mentioner
40
+ #
41
+ # @param [Mentioner] mentioner - the {Mentioner} to extract handles from
42
+ # @return [Array]
43
+ ###
44
+ def extract_handles_from_mentioner(mentioner)
45
+ content = extract_mentioner_content(mentioner)
46
+ handles = content.scan(handle_regexp).map { |handle| handle.gsub("#{mention_prefix}","") }
47
+ end
48
+
49
+ ###
50
+ # Extracts the mentioner content
51
+ #
52
+ # @param [Mentioner] mentioner - the {Mentioner} to extract content from
53
+ # @return [String]
54
+ ###
55
+ def extract_mentioner_content(mentioner)
56
+ raise "Must be implemented in subclass"
57
+ end
58
+
59
+ ###
60
+ # Finds mentionees by handles
61
+ #
62
+ # @param [Array] handles - the array of {Mentionee} handles to find
63
+ # @return [Array]
64
+ ###
65
+ def find_mentionees_by_handles(*handles)
66
+ raise "Must be implemented in subclass"
67
+ end
68
+
69
+ ###
70
+ # Process mentions
71
+ #
72
+ # @param [Mentioner] mentioner - the {Mentioner} to process mentions from
73
+ ###
74
+ def process_mentions(mentioner)
75
+ handles = extract_handles_from_mentioner(mentioner)
76
+ mentionees = find_mentionees_by_handles(handles)
77
+
78
+ mentionees.each do |mentionee|
79
+ if process_before_callbacks(mentioner, mentionee)
80
+ if mentioner.mention(mentionee)
81
+ process_after_callbacks(mentioner, mentionee)
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ private
88
+ ###
89
+ # Retrieves the handle regexp
90
+ #
91
+ # @return [Regexp]
92
+ ###
93
+ def handle_regexp
94
+ /(?<!\w)#{mention_prefix}\w+/
95
+ end
96
+
97
+ ###
98
+ # Returns the mention prefix
99
+ #
100
+ # @return [String]
101
+ ###
102
+ def mention_prefix
103
+ "@"
104
+ end
105
+
106
+ ###
107
+ # Process after callbacks
108
+ #
109
+ # @param [Mentioner] mentioner - the mentioner of the callback
110
+ # @param [Mentionee] mentionee - the mentionee of the callback
111
+ ###
112
+ def process_after_callbacks(mentioner, mentionee)
113
+ result = true
114
+ @callbacks[:after].each do |callback|
115
+ unless callback.call(mentioner, mentionee)
116
+ result = false
117
+ break
118
+ end
119
+ end
120
+ result
121
+ end
122
+
123
+ ###
124
+ # Process before callbacks
125
+ #
126
+ # @param [Mentioner] mentioner - the mentioner of the callback
127
+ # @param [Mentionee] mentionee - the mentionee of the callback
128
+ ###
129
+ def process_before_callbacks(mentioner, mentionee)
130
+ result = true
131
+ @callbacks[:before].each do |callback|
132
+ unless callback.call(mentioner, mentionee)
133
+ result = false
134
+ break
135
+ end
136
+ end
137
+ result
138
+ end
139
+ end
140
+ end
141
+
@@ -0,0 +1,58 @@
1
+ ###
2
+ # MentionSystem module
3
+ #
4
+ # This module defines common behavior in mention system
5
+ ###
6
+ module MentionSystem
7
+ ###
8
+ # Mentionee module
9
+ #
10
+ # This module defines mentionee behavior in mention system
11
+ ###
12
+ module Mentionee
13
+ ###
14
+ # Extends ActiveSupport::Concern
15
+ ###
16
+ extend ActiveSupport::Concern
17
+
18
+ ###
19
+ # Included configuration
20
+ ###
21
+ included do
22
+ ###
23
+ # Has many mentioners association configuration
24
+ ###
25
+ has_many :mentioners, class_name: "MentionSystem::Mention", as: :mentionee, dependent: :destroy
26
+ end
27
+
28
+ ###
29
+ # Specifies if self can be mentioned by {Mentioner} objects
30
+ #
31
+ # @return [Boolean]
32
+ ###
33
+ def is_mentionee?
34
+ true
35
+ end
36
+
37
+ ###
38
+ # Specifies if self is mentioned by a {Mentioner} object
39
+ #
40
+ # @param [Mentioner] mentioner - the {Mentioner} object to test against
41
+ # @return [Boolean]
42
+ ###
43
+ def mentioned_by?(mentioner)
44
+ Mention.mentions?(mentioner, self)
45
+ end
46
+
47
+ ###
48
+ # Retrieves a scope of {Mention} objects that mentions self filtered {Mentioner} type
49
+ #
50
+ # @param [Class] klass - the {Class} to filter
51
+ # @return [ActiveRecord::Relation]
52
+ ###
53
+ def mentioners_by(klass)
54
+ Mention.scope_by_mentionee(self).scope_by_mentioner_type(klass)
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,88 @@
1
+ ###
2
+ # MentionSystem module
3
+ #
4
+ # This module defines common behavior in mention system
5
+ ###
6
+ module MentionSystem
7
+ ###
8
+ # Mentioner module
9
+ #
10
+ # This module defines mentioner behavior in mention system
11
+ ###
12
+ module Mentioner
13
+ ###
14
+ # Extends ActiveSupport::Concern
15
+ ###
16
+ extend ActiveSupport::Concern
17
+
18
+ ###
19
+ # Included configuration
20
+ ###
21
+ included do
22
+ ###
23
+ # Has many mentionees association configuration
24
+ ###
25
+ has_many :mentionees, class_name: "MentionSystem::Mention", as: :mentioner, dependent: :destroy
26
+ end
27
+
28
+ ###
29
+ # Specifies if self can mention {Mentionee} objects
30
+ #
31
+ # @return [Boolean]
32
+ ###
33
+ def is_mentioner?
34
+ true
35
+ end
36
+
37
+ ###
38
+ # Creates a {Mention} relationship between self and a {Mentionee} object
39
+ #
40
+ # @param [Mentionee] mentionee - the mentionee of the {Mention} relationship
41
+ # @return [Boolean]
42
+ ###
43
+ def mention(mentionee)
44
+ Mention.mention(self, mentionee)
45
+ end
46
+
47
+ ###
48
+ # Destroys a {Mention} relationship between self and a {Mentionee} object
49
+ #
50
+ # @param [Mentionee] mentionee - the mentionee of the {Mention} relationship
51
+ # @return [Boolean]
52
+ ###
53
+ def unmention(mentionee)
54
+ Mention.unmention(self, mentionee)
55
+ end
56
+
57
+ ###
58
+ # Toggles a {Mention} relationship between self and a {Mentionee} object
59
+ #
60
+ # @param [Mentionee] mentionee - the mentionee of the {Mention} relationship
61
+ # @return [Boolean]
62
+ ###
63
+ def toggle_mention(mentionee)
64
+ Mention.toggle_mention(self, mentionee)
65
+ end
66
+
67
+ ###
68
+ # Specifies if self mentions a {Mentioner} object
69
+ #
70
+ # @param [Mentionee] mentionee - the {Mentionee} object to test against
71
+ # @return [Boolean]
72
+ ###
73
+ def mentions?(mentionee)
74
+ Mention.mentions?(self, mentionee)
75
+ end
76
+
77
+ ###
78
+ # Retrieves a scope of {Mention} objects that are mentioned by self
79
+ #
80
+ # @param [Class] klass - the {Class} to include
81
+ # @return [ActiveRecord::Relation]
82
+ ###
83
+ def mentionees_by(klass)
84
+ Mention.scope_by_mentioner(self).scope_by_mentionee_type(klass)
85
+ end
86
+ end
87
+ end
88
+