ytag 0.0.1

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 (6) hide show
  1. data/README +62 -0
  2. data/lib/ytag.rb +24 -0
  3. data/lib/ytag/bundle.rb +15 -0
  4. data/lib/ytag/tag.rb +140 -0
  5. data/test/tagify.rb +259 -0
  6. metadata +83 -0
data/README ADDED
@@ -0,0 +1,62 @@
1
+ == What
2
+ Tagging library for Ruby
3
+
4
+ Provide a robust tagging API that solves the problems posed by Acidus:
5
+
6
+ 1. How to handle multiple words
7
+ 2. If/how to allow tag delimiter inside a tag
8
+ 3. Does letter case matter
9
+ 4. Punctuation and symbols
10
+ 5. Handling plural or singular words
11
+ 6. Date formating
12
+ 7. Multiple language support
13
+ 8. Colloquialisms/slang
14
+
15
+ YTag handles cases 1, 2, 3, and 4, as these are syntactic issues. Cases 5, 6,
16
+ 7, and 8 are more interesting. I think they should really be left to user
17
+ creativity. Case 6 is not a problem because YTag maintains independent date and
18
+ time stamps for tags, so even if I encode it in the tag in a weird manner, any
19
+ user will be able to get at an ISO-standard date/time stamp.
20
+
21
+ At the end of the day, YTag draws a lot of inspiration from Consumating [RIP]
22
+ and del.icio.us.
23
+
24
+ References:
25
+ http://neosmart.net/blog/2007/the-need-for-creating-tag-standards/
26
+ http://www.memestreams.net/users/acidus/blogid152074
27
+
28
+ == How
29
+ require 'rubygems'
30
+ require 'ytag'
31
+
32
+ Dependencies:
33
+ - HTMLEntities gem
34
+ - REX gem
35
+ - RCL gem
36
+
37
+ What you get:
38
+
39
+ YTag::Tag#new(name, user, active=true, hidden=false)
40
+ YTag::Tag#create
41
+ YTag::Tag#modify
42
+ YTag::Tag#access
43
+ YTag::Tag#print
44
+
45
+ YTag::tagify(tag)
46
+
47
+ == Install
48
+ To construct a Ruby gem, just type:
49
+
50
+ rake gem
51
+
52
+ To install it, type:
53
+
54
+ sudo gem install pkg/ytag-0.0.1.gem
55
+
56
+ == Notes
57
+ I haven't tested this code with YARV, so YMMV.
58
+
59
+ == Contribute
60
+ The source is availble at github: git://github.com/yesmar/ytag.git. Feel free
61
+ to clone it and implement your own awesome ideas. You can also send your
62
+ patches by email to yesmar[at]speakeasy[dot]net.
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ytag.rb
4
+ # yesmar@speakeasy.net
5
+
6
+ module YTag
7
+ YTag::NAME = 'ytag'
8
+ YTag::VERSION = '0.0.1'
9
+ YTag::COPYRIGHT = 'Copyright (c) 2008 Ramsey Dow'
10
+ def self.copyright() YTag::COPYRIGHT end
11
+ def self.version() YTag::VERSION end
12
+ def self.libdir() File.expand_path(__FILE__).gsub(%r/\.rb$/, '') end
13
+ end
14
+
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+'/ytag')
16
+
17
+ require 'tag'
18
+ require 'bundle'
19
+
20
+ # TODO add more Tag unit tests
21
+ # TODO implement bundle
22
+ # TODO code up some examples
23
+
24
+ raise RuntimeError, 'This library is for require only' if $0 == __FILE__
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # bundle.rb
4
+ # yesmar@speakeasy.net
5
+
6
+ require 'rubygems'
7
+ require 'htmlentities'
8
+ require 'rex'
9
+ require 'rcl'
10
+
11
+ module YTag
12
+ class Bundle
13
+
14
+ end
15
+ end
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # tag.rb
4
+ # yesmar@speakeasy.net
5
+
6
+ require 'rubygems'
7
+ require 'htmlentities'
8
+ require 'rex'
9
+ require 'rcl'
10
+
11
+ module YTag
12
+ class Tag
13
+ attr_reader :name, :user, :active, :hidden
14
+
15
+ MARKUP = {}
16
+ BOGUS = 'system:undefined'
17
+
18
+ def initialize(name, user, active=true, hidden=false)
19
+ raise ArgumentError, 'nil name' if name.nil?
20
+ raise ArgumentError, 'invalid name class' if name.class != String
21
+ raise ArgumentError, 'empty name' if name.empty?
22
+ raise ArgumentError, 'nil user' if user.nil?
23
+ raise ArgumentError, 'invalid user class' if user.class != String
24
+ raise ArgumentError, 'empty user' if user.empty?
25
+ raise ArgumentError, 'invalid active class' if \
26
+ active.class != TrueClass && active.class != FalseClass
27
+ raise ArgumentError, 'invalid hidden class' if \
28
+ hidden.class != TrueClass && hidden.class != FalseClass
29
+
30
+ @name = YTag::tagify(name)
31
+ @user = user
32
+ @active = active
33
+ @hidden = hidden
34
+ @timestamp = RCL::Timestamp.new
35
+
36
+ nil
37
+ end
38
+
39
+ def create
40
+ @timestamp.create
41
+ end
42
+
43
+ def modify
44
+ @timestamp.modify
45
+ end
46
+
47
+ def access
48
+ @timestamp.access
49
+ end
50
+
51
+ def print(stream=STDOUT)
52
+ raise 'nil stream' if stream.nil?
53
+ raise 'invalid stream class' if stream.class != IO
54
+
55
+ @timestamp.update_access
56
+
57
+ stream << "#{@name} ["
58
+ stream << 'in' if !@active
59
+ stream << 'active, '
60
+ if !@hidden
61
+ stream << 'public'
62
+ else
63
+ stream << 'private'
64
+ end
65
+ stream << "]\n"
66
+
67
+ stream << "+ added by #{@user} on #{@timestamp.create}\n"
68
+ stream << "+ last accessed on #{@timestamp.access}\n"
69
+
70
+ nil
71
+ end
72
+
73
+ private
74
+
75
+ @name
76
+ @user
77
+ @active
78
+ @hidden
79
+ @timestamp
80
+ end
81
+
82
+ def self.tagify(tag)
83
+ raise ArgumentError, 'nil tag' if tag.nil?
84
+ raise ArgumentError, 'invalid tag class' if tag.class != String
85
+ raise ArgumentError, 'empty tag' if tag.empty?
86
+
87
+ # scrub all markup/scripting
88
+ tag.scrub!(Tag::MARKUP)
89
+
90
+ # from here on, tag may become empty and/or nil after any given operation
91
+
92
+ # encode HTML entities
93
+ tag = HTMLEntities.encode_entities(tag, :basic, :named) \
94
+ if !tag.nil? && !tag.empty?
95
+
96
+ # transform &amp; => _amp_
97
+ tag.gsub!('&amp;', '_amp_') if !tag.nil? && !tag.empty?
98
+
99
+ # transform & => _amp_
100
+ tag.gsub!('&', '_amp_') if !tag.nil? && !tag.empty?
101
+
102
+ # transform ? => _qm
103
+ tag.gsub!('?', '_qm') if !tag.nil? && !tag.empty?
104
+
105
+ # transform ! => _xpt
106
+ tag.gsub!('!', '_xpt') if !tag.nil? && !tag.empty?
107
+
108
+ # transform / => _fs_
109
+ tag.gsub!('/', '_fs_') if !tag.nil? && !tag.empty?
110
+
111
+ # transform \ => _bs_
112
+ tag.gsub!('\\', '_bs_') if !tag.nil? && !tag.empty?
113
+
114
+ # compress whitespace
115
+ tag.squeeze(' \t') if !tag.nil? && !tag.empty?
116
+
117
+ # delete undefined characters
118
+ tag.delete!('=~@#$%^*()+[]{}|;:\'\"<>') if !tag.nil? && !tag.empty?
119
+
120
+ # transform illegal separators
121
+ tag.tr!(' ,.-', '_') if !tag.nil? && !tag.empty?
122
+
123
+ # compress underscores
124
+ tag.squeeze!('_') if !tag.nil? && !tag.empty?
125
+
126
+ # remove preceding underscore
127
+ tag = tag[1..-1] if !tag.nil? && !tag.empty? && tag[0].chr == '_'
128
+
129
+ # remove trailing underscore
130
+ tag = tag[0..tag.length-2] if !tag.nil? && !tag.empty? && tag[-1].chr == '_'
131
+
132
+ # downcase
133
+ tag.downcase! if !tag.nil? && !tag.empty?
134
+
135
+ # handle nil or empty tags
136
+ tag = Tag::BOGUS if tag.nil? || tag.empty?
137
+
138
+ tag
139
+ end
140
+ end
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # tagify.rb
4
+ # YTag::tagify unit tests
5
+
6
+ require 'test/unit'
7
+
8
+ require 'pathname'
9
+ dir = Pathname.new(File.expand_path(__FILE__)).realpath
10
+ require File.join(File.dirname(dir.to_s), '../lib/ytag')
11
+
12
+ class TagifyTests < Test::Unit::TestCase
13
+ def test_nil_string
14
+ expected = nil
15
+ actual = nil
16
+
17
+ assert_raise ArgumentError do
18
+ actual = YTag::tagify(nil)
19
+ end
20
+
21
+ assert_nil(actual)
22
+ assert_instance_of(NilClass, actual)
23
+ assert_equal(expected, actual)
24
+ end
25
+
26
+ def test_invalid_class
27
+ expected = nil
28
+ actual = nil
29
+
30
+ assert_raise ArgumentError do
31
+ actual = YTag::tagify(TrueClass)
32
+ end
33
+
34
+ assert_nil(actual)
35
+ assert_instance_of(NilClass, actual)
36
+ assert_equal(expected, actual)
37
+ end
38
+
39
+ def test_empty_string
40
+ expected = nil
41
+ actual = nil
42
+
43
+ assert_raise ArgumentError do
44
+ actual = YTag::tagify('')
45
+ end
46
+
47
+ assert_nil(actual)
48
+ assert_instance_of(NilClass, actual)
49
+ assert_equal(expected, actual)
50
+ end
51
+
52
+ def test_html_entities_1
53
+ expected = 'amp_amp_lt_amp_gt'
54
+ actual = nil
55
+
56
+ assert_nothing_raised do
57
+ actual = YTag::tagify('&<>')
58
+ end
59
+
60
+ assert_not_nil(actual)
61
+ assert_instance_of(String, actual)
62
+ assert_equal(expected, actual)
63
+ end
64
+
65
+ def test_html_entities_2
66
+ expected = 'abc_amp_auml'
67
+ actual = nil
68
+
69
+ assert_nothing_raised do
70
+ actual = YTag::tagify("abc\303\244")
71
+ end
72
+
73
+ assert_not_nil(actual)
74
+ assert_instance_of(String, actual)
75
+ assert_equal(expected, actual)
76
+ end
77
+
78
+ def test_markup
79
+ expected = YTag::Tag::BOGUS
80
+ actual = nil
81
+
82
+ assert_nothing_raised do
83
+ actual = YTag::tagify("<img src=\"javascript:alert('xss');\">")
84
+ end
85
+
86
+ assert_not_nil(actual)
87
+ assert_instance_of(String, actual)
88
+ assert_equal(expected, actual)
89
+ end
90
+
91
+ def test_script_1
92
+ expected = 'document_cookie'
93
+ actual = nil
94
+
95
+ assert_nothing_raised do
96
+ actual = YTag::tagify('<script>document.cookie</script>')
97
+ end
98
+
99
+ assert_not_nil(actual)
100
+ assert_instance_of(String, actual)
101
+ assert_equal(expected, actual)
102
+ end
103
+
104
+ def test_script_2
105
+ expected = YTag::Tag::BOGUS
106
+ actual = nil
107
+
108
+ assert_nothing_raised do
109
+ actual = YTag::tagify('<script></script>')
110
+ end
111
+
112
+ assert_not_nil(actual)
113
+ assert_instance_of(String, actual)
114
+ assert_equal(expected, actual)
115
+ end
116
+
117
+ def test_whitespace_compression
118
+ expected = 'mac_os_x'
119
+ actual = nil
120
+
121
+ assert_nothing_raised do
122
+ actual = YTag::tagify(' Mac OS X ')
123
+ end
124
+
125
+ assert_not_nil(actual)
126
+ assert_instance_of(String, actual)
127
+ assert_equal(expected, actual)
128
+ end
129
+
130
+ def test_underscore_compression
131
+ expected = 'foo_bar'
132
+ actual = nil
133
+
134
+ assert_nothing_raised do
135
+ actual = YTag::tagify('______foo__________bar___________')
136
+ end
137
+
138
+ assert_not_nil(actual)
139
+ assert_instance_of(String, actual)
140
+ assert_equal(expected, actual)
141
+ end
142
+
143
+ def test_undefined_characters
144
+ expected = 'amp_apos_bs_amp_quot_amp_lt_amp_gt'
145
+ actual = nil
146
+
147
+ assert_nothing_raised do
148
+ actual = YTag::tagify('=~@#$%^*()+[]{}|;:\'\"<>')
149
+ end
150
+
151
+ assert_not_nil(actual)
152
+ assert_instance_of(String, actual)
153
+ assert_equal(expected, actual)
154
+ end
155
+
156
+ def test_illegal_separators
157
+ expected = 'a_b_c_d_e'
158
+ actual = nil
159
+
160
+ assert_nothing_raised do
161
+ actual = YTag::tagify('a b,c.d-e')
162
+ end
163
+
164
+ assert_not_nil(actual)
165
+ assert_instance_of(String, actual)
166
+ assert_equal(expected, actual)
167
+ end
168
+
169
+ def test_preceding_separarator
170
+ expected = 'tag'
171
+ actual = nil
172
+
173
+ assert_nothing_raised do
174
+ actual = YTag::tagify('_tag')
175
+ end
176
+
177
+ assert_not_nil(actual)
178
+ assert_instance_of(String, actual)
179
+ assert_equal(expected, actual)
180
+ end
181
+
182
+ def test_trailing_separator
183
+ expected = 'tag'
184
+ actual = nil
185
+
186
+ assert_nothing_raised do
187
+ actual = YTag::tagify('tag_')
188
+ end
189
+
190
+ assert_not_nil(actual)
191
+ assert_instance_of(String, actual)
192
+ assert_equal(expected, actual)
193
+ end
194
+
195
+ def test_ampersand
196
+ expected = 'a_amp_b'
197
+ actual = nil
198
+
199
+ assert_nothing_raised do
200
+ actual = YTag::tagify('a & b')
201
+ end
202
+
203
+ assert_not_nil(actual)
204
+ assert_instance_of(String, actual)
205
+ assert_equal(expected, actual)
206
+ end
207
+
208
+ def test_question_mark
209
+ expected = 'wtf_qm'
210
+ actual = nil
211
+
212
+ assert_nothing_raised do
213
+ actual = YTag::tagify('wtf?')
214
+ end
215
+
216
+ assert_not_nil(actual)
217
+ assert_instance_of(String, actual)
218
+ assert_equal(expected, actual)
219
+ end
220
+
221
+ def test_exclamation_mark
222
+ expected = 'ausgezeichnet_xpt'
223
+ actual = nil
224
+
225
+ assert_nothing_raised do
226
+ actual = YTag::tagify('ausgezeichnet_xpt')
227
+ end
228
+
229
+ assert_not_nil(actual)
230
+ assert_instance_of(String, actual)
231
+ assert_equal(expected, actual)
232
+ end
233
+
234
+ def test_forward_slash
235
+ expected = 'fs_etc_fs_passwd'
236
+ actual = nil
237
+
238
+ assert_nothing_raised do
239
+ actual = YTag::tagify('/etc/passwd')
240
+ end
241
+
242
+ assert_not_nil(actual)
243
+ assert_instance_of(String, actual)
244
+ assert_equal(expected, actual)
245
+ end
246
+
247
+ def test_backward_slash
248
+ expected = 'c_bs_windows_bs_system32'
249
+ actual = nil
250
+
251
+ assert_nothing_raised do
252
+ actual = YTag::tagify('C:\\WINDOWS\\system32')
253
+ end
254
+
255
+ assert_not_nil(actual)
256
+ assert_instance_of(String, actual)
257
+ assert_equal(expected, actual)
258
+ end
259
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ytag
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ramsey Dow
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-01 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: htmlentities
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 4.0.0
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: rex
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 0.0.4
32
+ version:
33
+ - !ruby/object:Gem::Dependency
34
+ name: rcl
35
+ version_requirement:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.5
41
+ version:
42
+ description:
43
+ email: yesmar @nospam@ speakeasy.net
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ extra_rdoc_files:
49
+ - README
50
+ files:
51
+ - lib/ytag.rb
52
+ - lib/ytag/bundle.rb
53
+ - lib/ytag/tag.rb
54
+ - test/tagify.rb
55
+ - README
56
+ has_rdoc: true
57
+ homepage: http://ytag.rubyforge.org/
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ requirements: []
76
+
77
+ rubyforge_project: http://rubyforge.org/projects/ytag/
78
+ rubygems_version: 1.0.1
79
+ signing_key:
80
+ specification_version: 2
81
+ summary: Tagging library for Ruby
82
+ test_files:
83
+ - test/tagify.rb