hashtags 0.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.
@@ -0,0 +1,92 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ module Hashtags
4
+ class Resource < Base
5
+ # implement as resource class in your application
6
+ def self.resource_class
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def self.find_by_resource_type(resource_type)
11
+ descendants.detect{ |cls| cls.resource_name.to_s == resource_type.to_s }
12
+ end
13
+
14
+ def self.resource_name
15
+ resource_class.to_s.demodulize.underscore
16
+ end
17
+
18
+ def self.cache_key
19
+ resource_class.cache_key
20
+ end
21
+
22
+ def self.trigger
23
+ '#'
24
+ end
25
+
26
+ # name of attribute to be used in the tag
27
+ # #resource_name:<tag_attribute>(id)
28
+ # (for example :to_s)
29
+ def self.tag_attribute
30
+ raise NotImplemented
31
+ end
32
+
33
+ # the tags will be replaced by this attribute
34
+ # (for example :link_to)
35
+ def self.result_attribute
36
+ raise NotImplemented
37
+ end
38
+
39
+ def self.regexp
40
+ /#{Regexp.escape(trigger)}#{resource_name}:(.+?)\((.+?)\b\)/i
41
+ end
42
+
43
+ def self.help_values
44
+ [resource_name]
45
+ end
46
+
47
+ # ---------------------------------------------------------------------
48
+ # JS
49
+
50
+ def self.match_regexp
51
+ /(#{Regexp.escape(trigger)}#{resource_name}\:)(\w{1,})\z/
52
+ end
53
+
54
+ def self.match_index
55
+ 2
56
+ end
57
+
58
+ def self.match_template
59
+ "{{ #{tag_attribute} }}"
60
+ end
61
+
62
+ def self.replace
63
+ "#{trigger}#{resource_name}:{{ #{tag_attribute} }}({{ id }})"
64
+ end
65
+
66
+ def self.template
67
+ "{{ #{tag_attribute} }}"
68
+ end
69
+
70
+ private # =============================================================
71
+
72
+ def hashtag(match)
73
+ return unless id = match[self.class.match_index]
74
+ return unless res = resource(id)
75
+ Handlebars::Context.new
76
+ .compile(self.class.replace)
77
+ .call(id: res.id.to_s, self.class.tag_attribute => res.send(self.class.tag_attribute))
78
+ end
79
+
80
+ def markup(match)
81
+ return unless id = match[self.class.match_index]
82
+ return unless res = resource(id)
83
+ res.send(self.class.result_attribute)
84
+ end
85
+
86
+ # finds resource based on tag_attribute_value
87
+ # (for example resource_class.find(value))
88
+ def resource(value)
89
+ raise NotImplemented
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,56 @@
1
+ require 'active_support/descendants_tracker'
2
+
3
+ module Hashtags
4
+ class ResourceType < Base
5
+ def self.trigger
6
+ '#'
7
+ end
8
+
9
+ def self.regexp
10
+ /#{trigger}(.+?)\b/i
11
+ end
12
+
13
+ def self.resource_classes
14
+ Resource.descendants
15
+ end
16
+
17
+ # ---------------------------------------------------------------------
18
+ # JS
19
+
20
+ def self.match_regexp
21
+ /(\A#{trigger}|\s#{trigger})(\w*)\z/
22
+ end
23
+
24
+ def self.match_index
25
+ 2
26
+ end
27
+
28
+ def self.replace
29
+ '$1{{ this }}:'
30
+ end
31
+
32
+ def self.template
33
+ '{{ this }}'
34
+ end
35
+
36
+ # ---------------------------------------------------------------------
37
+
38
+ def self.values(hashtag_classes = Resource.descendants)
39
+ (resource_classes & hashtag_classes).map(&:resource_name)
40
+ end
41
+
42
+ def self.cache_key
43
+ resource_classes.map(&:resource_name)
44
+ end
45
+
46
+ private # =============================================================
47
+
48
+ def hashtag(match)
49
+ # do nothing
50
+ end
51
+
52
+ def markup(match)
53
+ # do nothing
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,92 @@
1
+ require 'handlebars'
2
+
3
+ module Hashtags
4
+ class User < Base
5
+ # implement as user class in your application
6
+ def self.resource_class
7
+ raise NotImplemented
8
+ end
9
+
10
+ def self.resource_name
11
+ resource_class.to_s.demodulize.underscore
12
+ end
13
+
14
+ # override for custom cache_key
15
+ def self.cache_key
16
+ resource_class.cache_key
17
+ end
18
+
19
+ def self.trigger
20
+ '@'
21
+ end
22
+
23
+ # name of attribute to be used in the tag
24
+ # @<tag_attribute> (for example :username)
25
+ def self.tag_attribute
26
+ raise NotImplemented
27
+ end
28
+
29
+ # the tags will be replaced by this attribute
30
+ # (for example :full_name)
31
+ def self.result_attribute
32
+ raise NotImplemented
33
+ end
34
+
35
+ def self.regexp
36
+ /#{Regexp.escape(trigger)}(\w+)/i
37
+ end
38
+
39
+ def self.help_values
40
+ [resource_name]
41
+ end
42
+
43
+ # ---------------------------------------------------------------------
44
+ # JS
45
+
46
+ def self.match_regexp
47
+ /(\A#{Regexp.escape(trigger)}|\s#{Regexp.escape(trigger)})(\w{1,})\z/
48
+ end
49
+
50
+ def self.match_index
51
+ 2
52
+ end
53
+
54
+ def self.match_template
55
+ "{{ #{tag_attribute} }}"
56
+ end
57
+
58
+ def self.replace
59
+ "#{trigger}{{ #{tag_attribute} }}"
60
+ end
61
+
62
+ def self.template
63
+ "{{ #{tag_attribute} }}"
64
+ end
65
+
66
+ private # =============================================================
67
+
68
+ # updates found tags with tag value from resource
69
+ # @jtschichold => @JTschichold
70
+ def hashtag(match)
71
+ return unless id = match[self.class.match_index-1]
72
+ return unless user = resource(id)
73
+ Handlebars::Context.new
74
+ .compile(self.class.replace)
75
+ .call(self.class.tag_attribute => user.send(self.class.tag_attribute))
76
+ end
77
+
78
+ # replaces tags with result from resource
79
+ # @JTschichold => Jan Tschichold
80
+ def markup(match)
81
+ return unless id = match[self.class.match_index-1]
82
+ return unless user = resource(id)
83
+ user.send(self.class.result_attribute)
84
+ end
85
+
86
+ # finds resource based on tag_attribute_value
87
+ # for example: resource_class.where(username: tag_attribute_value).first
88
+ def resource(value)
89
+ raise NotImplemented
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,59 @@
1
+ module Hashtags
2
+ class Variable < Base
3
+ def self.trigger
4
+ '$'
5
+ end
6
+
7
+ def self.regexp
8
+ /#{Regexp.escape(trigger)}(.+?)\b/i
9
+ end
10
+
11
+ def self.values(hashtag_classes = Variable.descendants)
12
+ raise NotImplemented
13
+ end
14
+
15
+ def self.help_values
16
+ values
17
+ end
18
+
19
+ # ---------------------------------------------------------------------
20
+ # JS
21
+
22
+ def self.match_regexp
23
+ /(\A#{Regexp.escape(trigger)}|\s#{Regexp.escape(trigger)})(\w{1,})\z/
24
+ end
25
+
26
+ def self.match_index
27
+ 2
28
+ end
29
+
30
+ def self.replace
31
+ "#{trigger}{{ this }}"
32
+ end
33
+
34
+ def self.template
35
+ '{{ this }}'
36
+ end
37
+
38
+ def self.strategy(hashtag_classes)
39
+ super.tap { |obj| obj[:values] = compound_values(hashtag_classes) }
40
+ end
41
+
42
+ def self.compound_values(hashtag_classes)
43
+ cls = Builder.new.filter_classes(variable_classes & hashtag_classes)
44
+ cls.map { |i| i.values(hashtag_classes) }.flatten.compact
45
+ end
46
+
47
+ private # =============================================================
48
+
49
+ def hashtag(match)
50
+ return unless name(match)
51
+ [self.class.trigger, name(match)].join
52
+ end
53
+
54
+ def name(match)
55
+ return unless self.class.values.include?(match[1])
56
+ match[1]
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ module Hashtags
2
+ VERSION = '0.1.0'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,243 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hashtags
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tomas Celizna
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: handlebars
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails-assets-jquery-textcomplete
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rails-assets-handlebars
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: minitest
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '5.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '5.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: database_cleaner
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: mongoid
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '5.0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '5.0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: slim
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description:
182
+ email:
183
+ - tomas.celizna@gmail.com
184
+ executables: []
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - ".gitignore"
189
+ - ".travis.yml"
190
+ - Gemfile
191
+ - Guardfile
192
+ - LICENSE.txt
193
+ - README.md
194
+ - Rakefile
195
+ - app/controllers/hashtags/resources_controller.rb
196
+ - app/helpers/hashtags/view_helper.rb
197
+ - app/views/hashtags/_help.slim
198
+ - bin/console
199
+ - bin/setup
200
+ - config/locales/.gitkeep
201
+ - config/locales/hashtags/builder.en.yml
202
+ - config/routes.rb
203
+ - hashtags.gemspec
204
+ - lib/assets/javascripts/hashtags.js
205
+ - lib/assets/javascripts/hashtags/hashtags.coffee
206
+ - lib/assets/stylesheets/hashtags.css
207
+ - lib/assets/stylesheets/hashtags/help.scss
208
+ - lib/assets/stylesheets/hashtags/textcomplete.scss
209
+ - lib/hashtags.rb
210
+ - lib/hashtags/base.rb
211
+ - lib/hashtags/builder.rb
212
+ - lib/hashtags/engine.rb
213
+ - lib/hashtags/mongoid_extension.rb
214
+ - lib/hashtags/resource.rb
215
+ - lib/hashtags/resource_type.rb
216
+ - lib/hashtags/user.rb
217
+ - lib/hashtags/variable.rb
218
+ - lib/hashtags/version.rb
219
+ homepage: https://github.com/tomasc/hashtags
220
+ licenses:
221
+ - MIT
222
+ metadata: {}
223
+ post_install_message:
224
+ rdoc_options: []
225
+ require_paths:
226
+ - lib
227
+ required_ruby_version: !ruby/object:Gem::Requirement
228
+ requirements:
229
+ - - ">="
230
+ - !ruby/object:Gem::Version
231
+ version: '0'
232
+ required_rubygems_version: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ requirements: []
238
+ rubyforge_project:
239
+ rubygems_version: 2.4.5.1
240
+ signing_key:
241
+ specification_version: 4
242
+ summary: Rails engine to facilitate inline text hashtags.
243
+ test_files: []