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.
- checksums.yaml +7 -0
- data/.empty +0 -0
- data/.gitignore +15 -0
- data/.keep +0 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +23 -0
- data/Appraisals +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +170 -0
- data/Rakefile +8 -0
- data/gemfiles/.empty +0 -0
- data/gemfiles/.gitignore +0 -0
- data/gemfiles/.keep +0 -0
- data/gemfiles/rails4.1.gemfile +7 -0
- data/gemfiles/rails4.2.gemfile +7 -0
- data/lib/.empty +0 -0
- data/lib/.gitignore +0 -0
- data/lib/.keep +0 -0
- data/lib/generators/.empty +0 -0
- data/lib/generators/.gitignore +0 -0
- data/lib/generators/.keep +0 -0
- data/lib/generators/mention_system/.empty +0 -0
- data/lib/generators/mention_system/.gitignore +0 -0
- data/lib/generators/mention_system/.keep +0 -0
- data/lib/generators/mention_system/mention_system_generator.rb +46 -0
- data/lib/generators/mention_system/templates/.empty +0 -0
- data/lib/generators/mention_system/templates/.gitignore +0 -0
- data/lib/generators/mention_system/templates/.keep +0 -0
- data/lib/generators/mention_system/templates/migration.rb +47 -0
- data/lib/mention_system.rb +46 -0
- data/lib/mention_system/.empty +0 -0
- data/lib/mention_system/.gitignore +0 -0
- data/lib/mention_system/.keep +0 -0
- data/lib/mention_system/mention.rb +155 -0
- data/lib/mention_system/mention_processor.rb +141 -0
- data/lib/mention_system/mentionee.rb +58 -0
- data/lib/mention_system/mentioner.rb +88 -0
- data/lib/mention_system/version.rb +12 -0
- data/mention_system.gemspec +31 -0
- data/spec/.empty +0 -0
- data/spec/.gitignore +0 -0
- data/spec/.keep +0 -0
- data/spec/db/.empty +0 -0
- data/spec/db/.gitignore +0 -0
- data/spec/db/.keep +0 -0
- data/spec/db/migrate/.empty +0 -0
- data/spec/db/migrate/.gitignore +0 -0
- data/spec/db/migrate/.keep +0 -0
- data/spec/db/migrate/20140926000000_create_mentions.rb +47 -0
- data/spec/db/migrate/20140926000005_create_dummy_mentioners.rb +22 -0
- data/spec/db/migrate/20140926000010_create_dummy_mentionees.rb +22 -0
- data/spec/mention_system/.empty +0 -0
- data/spec/mention_system/.gitignore +0 -0
- data/spec/mention_system/.keep +0 -0
- data/spec/mention_system/mention_processor_spec.rb +155 -0
- data/spec/mention_system/mention_spec.rb +177 -0
- data/spec/mention_system/mentionee_spec.rb +69 -0
- data/spec/mention_system/mentioner_spec.rb +96 -0
- data/spec/spec_helper.rb +116 -0
- data/spec/support/.empty +0 -0
- data/spec/support/.gitignore +0 -0
- data/spec/support/.keep +0 -0
- data/spec/support/active_record.rb +12 -0
- data/spec/support/shoulda_matchers.rb +2 -0
- 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
|
+
|