ytag 0.0.1

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