rcl 0.0.2
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.
- data/README +107 -0
- data/lib/rcl.rb +35 -0
- data/lib/rcl/base.rb +64 -0
- data/lib/rcl/perms.rb +103 -0
- data/lib/rcl/shell.rb +167 -0
- data/lib/rcl/timestamp.rb +92 -0
- data/lib/rcl/token.rb +36 -0
- data/lib/rcl/url.rb +36 -0
- data/lib/rcl/xml.rb +55 -0
- metadata +61 -0
data/README
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
== What
|
2
|
+
Ramsey's Common Library version 0.0.3
|
3
|
+
|
4
|
+
This is simply a collection of Ruby modules that perform useful tasks. There
|
5
|
+
are methods that do simple things like check permissions on files and
|
6
|
+
directories, create and manipulate timestamps and authentication tokens, and
|
7
|
+
so on. There are a couple of interesting modules that do interesting things
|
8
|
+
like RELAXNG schema validation of XML files and an interactive command shell
|
9
|
+
with history (with big props to the GNU Readline library).
|
10
|
+
|
11
|
+
Briefly, the modules and their respective methods are:
|
12
|
+
|
13
|
+
Base#initialize
|
14
|
+
Base#dump
|
15
|
+
Base#create
|
16
|
+
Base#modify
|
17
|
+
Base#update_modify
|
18
|
+
Base#access
|
19
|
+
Base#update_access
|
20
|
+
|
21
|
+
Perms#check_dir
|
22
|
+
Perms#check_dir_r
|
23
|
+
Perms#check_dir_w
|
24
|
+
Perms#check_dir_rw
|
25
|
+
Perms#check_file
|
26
|
+
Perms#check_file_r
|
27
|
+
Perms#check_file_w
|
28
|
+
Perms#check_file_rw
|
29
|
+
Perms#check_owned
|
30
|
+
|
31
|
+
Shell#initialize
|
32
|
+
Shell#register
|
33
|
+
Shell#unregister
|
34
|
+
Shell#run
|
35
|
+
Shell#history
|
36
|
+
|
37
|
+
Timestamp#new
|
38
|
+
Timestamp#create
|
39
|
+
Timestamp#modify
|
40
|
+
Timestamp#access
|
41
|
+
Timestamp#update_create
|
42
|
+
Timestamp#update_modify
|
43
|
+
Timestamp#update
|
44
|
+
Timestamp#dump
|
45
|
+
|
46
|
+
Token#initialize
|
47
|
+
Token#authenticate
|
48
|
+
|
49
|
+
URL#encode
|
50
|
+
URL#decode
|
51
|
+
URL#encoded?
|
52
|
+
|
53
|
+
XML#preprocess
|
54
|
+
XML#validate
|
55
|
+
|
56
|
+
== How
|
57
|
+
require 'rubygems'
|
58
|
+
require 'rcl'
|
59
|
+
|
60
|
+
== Examples
|
61
|
+
When you run the example programs, do it like so:
|
62
|
+
|
63
|
+
ruby examples/shell.rb
|
64
|
+
|
65
|
+
Use these example programs to see how you might use and otherwise integrate RCL
|
66
|
+
functionality into your own programs.
|
67
|
+
|
68
|
+
== Install
|
69
|
+
I added a Rakefile and a gem spec. To build the gem, just type:
|
70
|
+
|
71
|
+
rake gem
|
72
|
+
|
73
|
+
To install the gem, just type:
|
74
|
+
|
75
|
+
sudo gem install rcl-0.0.3.gem
|
76
|
+
|
77
|
+
== Notes
|
78
|
+
I haven't tested this code with YARV, so YMMV.
|
79
|
+
|
80
|
+
A summary of the international standard date and time notation
|
81
|
+
http://www.cl.cam.ac.uk/~mgk25/iso-time.html
|
82
|
+
|
83
|
+
REXML support for RELAXNG document validation is incomplete and buggy. The
|
84
|
+
XML::preprocess method solves a particularly thorny issue which causes
|
85
|
+
REXML::RELAXNG to fail in the presence of whitespace due to formatting. Given
|
86
|
+
a pathname, this function will remove leading and trailing whitespace from
|
87
|
+
individual lines. The processed document will be returned to the caller for
|
88
|
+
further processing.
|
89
|
+
|
90
|
+
== External Code and Acknowledgements
|
91
|
+
Occasionally I run across interesting snippets of Ruby code on the 'net that
|
92
|
+
don't seem to have a reliable home. They could be orphaned projects or just a
|
93
|
+
random post on a mailing list somewhere. If I find the code to be useful, I
|
94
|
+
will add it to the lib/ext directory. Not wishing to steal anyone's thunder,
|
95
|
+
here are acknowledgements for the current contents of the lib/ext directory:
|
96
|
+
|
97
|
+
- ANSIColour 0.1 by Robert Ryan (rjr@rollmop.org)
|
98
|
+
http://raa.ruby-lang.org/project/term-ansicolour/
|
99
|
+
|
100
|
+
- dir.rb by Ara T. Howard (ara.t.howard@noaa.gov)
|
101
|
+
|
102
|
+
- YAML Helper by Xavier Shay
|
103
|
+
http://rhnh.net/projects/yaml+helper
|
104
|
+
|
105
|
+
I do not claim copyright or ownership of these included bits of code. I am
|
106
|
+
merely including them in one place because I use them all the time and wanted
|
107
|
+
to make them more available to my own projects.
|
data/lib/rcl.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# rcl.rb
|
4
|
+
# yesmar@speakeasy.net
|
5
|
+
|
6
|
+
module RCL
|
7
|
+
RCL::NAME = 'rcl'
|
8
|
+
RCL::VERSION = '0.0.2'
|
9
|
+
RCL::COPYRIGHT = 'Copyright (c) 2008 Ramsey Dow'
|
10
|
+
def self.copyright() RCL::COPYRIGHT end
|
11
|
+
def self.version() RCL::VERSION end
|
12
|
+
def self.libdir() File.expand_path(__FILE__).gsub(%r/\.rb$/, '') end
|
13
|
+
end
|
14
|
+
|
15
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__)+'/rcl/ext')
|
16
|
+
|
17
|
+
require 'ansicolour'
|
18
|
+
require 'dir'
|
19
|
+
require 'yaml_helper'
|
20
|
+
|
21
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__)+'/rcl')
|
22
|
+
|
23
|
+
require 'base'
|
24
|
+
require 'perms'
|
25
|
+
require 'shell'
|
26
|
+
require 'timestamp'
|
27
|
+
require 'token'
|
28
|
+
require 'url'
|
29
|
+
require 'xml'
|
30
|
+
|
31
|
+
# TODO: need to fix any lingering inheritance issues
|
32
|
+
# TODO: bad developer, no unit tests
|
33
|
+
# TODO: need to finish developing example programs
|
34
|
+
|
35
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
data/lib/rcl/base.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# base.rb
|
4
|
+
# yesmar@speakeasy.net
|
5
|
+
|
6
|
+
module RCL
|
7
|
+
class Base
|
8
|
+
# initialize instance
|
9
|
+
def initialize
|
10
|
+
@timestamp = Timestamp.new
|
11
|
+
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
# return creation time
|
16
|
+
def create
|
17
|
+
@timestamp.create
|
18
|
+
end
|
19
|
+
|
20
|
+
# return modification time
|
21
|
+
def modify
|
22
|
+
@timestamp.modify
|
23
|
+
end
|
24
|
+
|
25
|
+
# update modification time
|
26
|
+
def update_modify
|
27
|
+
@timestamp.update_modify
|
28
|
+
end
|
29
|
+
|
30
|
+
# return access time
|
31
|
+
def access
|
32
|
+
@timestamp.access
|
33
|
+
end
|
34
|
+
|
35
|
+
# update access time
|
36
|
+
def update_access
|
37
|
+
@timestamp.update_access
|
38
|
+
end
|
39
|
+
|
40
|
+
# dump instance state to specified output stream
|
41
|
+
def dump(indent=0, stream=STDOUT)
|
42
|
+
raise ArgumentError, 'nil indent' if indent.nil?
|
43
|
+
raise ArgumentError, 'invalid indent class' if indent.class != Fixnum
|
44
|
+
raise ArgumentError, 'indent range error' if indent < 0
|
45
|
+
raise ArgumentError, 'nil stream' if stream.nil?
|
46
|
+
raise ArgumentError, 'invalid stream class' if stream.class != IO
|
47
|
+
|
48
|
+
# instance
|
49
|
+
indent.times { stream << ' ' }
|
50
|
+
stream << "#{self.class}<#{self.object_id}> instance:\n"
|
51
|
+
|
52
|
+
indent += 2
|
53
|
+
|
54
|
+
# @timestamp
|
55
|
+
@timestamp.dump(indent, stream)
|
56
|
+
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
@timestamp
|
63
|
+
end
|
64
|
+
end
|
data/lib/rcl/perms.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# perms.rb
|
4
|
+
# yesmar@speakeasy.net
|
5
|
+
|
6
|
+
module RCL
|
7
|
+
module Perms
|
8
|
+
# check that specified directory exists
|
9
|
+
def self.check_dir(pathname)
|
10
|
+
raise ArgumentError, 'nil pathname' if pathname.nil?
|
11
|
+
raise ArgumentError, 'invalid pathname class' if pathname.class != String
|
12
|
+
raise ArgumentError, 'empty pathname' if pathname.empty?
|
13
|
+
raise ArgumentError, "#{pathname} does not exist" \
|
14
|
+
if !File.exists?(pathname)
|
15
|
+
raise ArgumentError, "#{pathname} is not a directory" \
|
16
|
+
if !File.directory?(pathname)
|
17
|
+
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
# check that specified directory exists and is readable
|
22
|
+
def self.check_dir_r(pathname)
|
23
|
+
check_dir(pathname)
|
24
|
+
raise ArgumenError, "#{pathname} is not readable" \
|
25
|
+
if !File.readable?(pathname)
|
26
|
+
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
# check that specified directory exists and is writable
|
31
|
+
def self.check_dir_w(pathname)
|
32
|
+
check_dir(pathname)
|
33
|
+
raise ArgumentError, "#{pathname} is not writable" \
|
34
|
+
if !File.writable?(pathname)
|
35
|
+
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
# check that specified directory exists and is both readable and writable
|
40
|
+
def self.check_dir_rw(pathname)
|
41
|
+
check_dir(pathname)
|
42
|
+
check_dir_r(pathname)
|
43
|
+
check_dir_w(pathname)
|
44
|
+
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
# check that specified file exists
|
49
|
+
def self.check_file(pathname)
|
50
|
+
raise ArgumentError, 'nil pathname' if pathname.nil?
|
51
|
+
raise ArgumentError, 'invalid pathname class' if pathname.class != String
|
52
|
+
raise ArgumentError, 'empty pathname' if pathname.empty?
|
53
|
+
raise ArgumentError, "#{pathname} does not exist" \
|
54
|
+
if !File.exist?(pathname)
|
55
|
+
raise ArgumentError, "#{pathname} is not a directory" \
|
56
|
+
if !File.file?(pathname)
|
57
|
+
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
# check that specified file exists and is readable
|
62
|
+
def self.check_file_r(pathname)
|
63
|
+
check_file(pathname)
|
64
|
+
raise ArgumentError, "#{pathname} is not readable" \
|
65
|
+
if !File.readable?(pathname)
|
66
|
+
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
# check that specified file exists and is writable
|
71
|
+
def self.check_file_w(pathname)
|
72
|
+
check_file(pathname)
|
73
|
+
raise ArgumentError, "#{pathname} is not writable" \
|
74
|
+
if !File.writable?(pathname)
|
75
|
+
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
# check that specified file exists and is both readable and writable
|
80
|
+
def self.check_file_rw(pathname)
|
81
|
+
check_file(pathname)
|
82
|
+
check_file_r(pathname)
|
83
|
+
check_file_w(pathname)
|
84
|
+
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
# check file group and ownership
|
89
|
+
def self.check_owned(pathname)
|
90
|
+
raise ArgumentError, 'nil pathname' if pathname.nil?
|
91
|
+
raise ArgumentError, 'invalid pathname class' if pathname.class != String
|
92
|
+
raise ArgumentError, 'empty pathname' if pathname.empty?
|
93
|
+
raise ArgumentError, "#{pathname} does not have correct group" \
|
94
|
+
if !File.grpowned?(pathname)
|
95
|
+
raise ArgumentError, "#{pathname} does not have correct ownership" \
|
96
|
+
if !File.owned?(pathname)
|
97
|
+
|
98
|
+
true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
data/lib/rcl/shell.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# shell.rb
|
4
|
+
# yesmar@speakeasy.net
|
5
|
+
|
6
|
+
require 'readline'
|
7
|
+
|
8
|
+
module RCL
|
9
|
+
class Shell < Base
|
10
|
+
attr_accessor :prompt
|
11
|
+
attr_reader :history
|
12
|
+
|
13
|
+
Command = Struct.new('COMMAND', :command, :timestamp)
|
14
|
+
|
15
|
+
def initialize(processor, banner, prompt=DefaultPrompt)
|
16
|
+
raise ArgumentError, 'nil processor' if processor.nil?
|
17
|
+
raise ArgumentError, 'invalid processor class' \
|
18
|
+
if processor.class != Symbol
|
19
|
+
if !banner.nil?
|
20
|
+
raise ArgumentError, 'invalid banner class' if banner.class != Symbol
|
21
|
+
end
|
22
|
+
raise ArgumentError, 'nil prompt' if prompt.nil?
|
23
|
+
raise ArgumentError, 'invalid prompt class' if prompt.class != String
|
24
|
+
|
25
|
+
@banner = banner
|
26
|
+
@process = processor
|
27
|
+
@commands = {}
|
28
|
+
@prompt = (prompt[prompt.length-1].chr != ' ') ? "#{prompt} " : prompt
|
29
|
+
@history = []
|
30
|
+
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# TODO: Shell#register needs love
|
35
|
+
def register(command, *args)
|
36
|
+
raise ArgumentError, 'nil command' if command.nil?
|
37
|
+
raise ArgumentError, 'invalid command class' if command.class != String
|
38
|
+
raise ArgumentError, 'empty command' if command.empty?
|
39
|
+
if !args.nil?
|
40
|
+
raise ArgumentError, 'invalid args class' if args.class != Array
|
41
|
+
raise ArgumentError, 'empty args' if args.empty?
|
42
|
+
args.each do |arg|
|
43
|
+
raise ArgumentError, 'nil arg' if arg.nil?
|
44
|
+
raise ArgumentError, 'invalid arg class' if arg.class != String
|
45
|
+
raise ArgumentError, 'empty arg' if arg.empty?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
@commands[command] = args
|
50
|
+
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
|
54
|
+
# TODO: Shell#unregister needs love
|
55
|
+
def unregister(command)
|
56
|
+
raise ArgumentError, 'nil command' if command.nil?
|
57
|
+
raise ArgumentError, 'invalid command class' if command.class != String
|
58
|
+
raise ArgumentError, 'empty command' if command.empty?
|
59
|
+
|
60
|
+
if @commands.has_key?(command)
|
61
|
+
return @commands.delete(command)
|
62
|
+
end
|
63
|
+
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def run(*args)
|
68
|
+
if !@banner.nil?
|
69
|
+
send(@banner)
|
70
|
+
puts
|
71
|
+
end
|
72
|
+
|
73
|
+
loop do
|
74
|
+
buffer = Readline::readline(@prompt, true)
|
75
|
+
break if buffer.nil?
|
76
|
+
buffer.chomp!
|
77
|
+
next if buffer.nil?
|
78
|
+
buffer.strip!
|
79
|
+
|
80
|
+
# double bang repeatsw last command
|
81
|
+
if buffer =~ /^!!$/
|
82
|
+
if !@history.last.nil?
|
83
|
+
@history << Command.new(@history.last.command, Time.now)
|
84
|
+
exec(@history.last.command)
|
85
|
+
else
|
86
|
+
puts '!!: event not found'
|
87
|
+
end
|
88
|
+
next
|
89
|
+
end
|
90
|
+
|
91
|
+
# repeat specified command from history buffer
|
92
|
+
if buffer =~ /^!(\-)?(\d*)$/
|
93
|
+
if $1.nil?
|
94
|
+
# forward bang history
|
95
|
+
pos = $2.to_i-1
|
96
|
+
if pos < 0 || pos > @history.size-1
|
97
|
+
puts "#{buffer}: event not found"
|
98
|
+
next
|
99
|
+
else
|
100
|
+
if !@history[pos].command.nil?
|
101
|
+
@history << Command.new(@history[pos].command, Time.now)
|
102
|
+
exec(@history[pos].command)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
else
|
106
|
+
# reverse bang history
|
107
|
+
pos = $2.to_i-1
|
108
|
+
if pos < 0 || pos > @history.size-1
|
109
|
+
puts "#{buffer}: event not found"
|
110
|
+
next
|
111
|
+
else
|
112
|
+
if !@history[pos].command.nil?
|
113
|
+
@history << Command.new(@history[-pos].command, Time.now)
|
114
|
+
exec(@history[-(pos+1)].command)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
next
|
119
|
+
end
|
120
|
+
|
121
|
+
next if buffer.empty?
|
122
|
+
|
123
|
+
@history << Command.new(buffer, Time.now)
|
124
|
+
exec(buffer)
|
125
|
+
end
|
126
|
+
|
127
|
+
puts
|
128
|
+
end
|
129
|
+
|
130
|
+
def history
|
131
|
+
i = 1
|
132
|
+
@history.each do |cb|
|
133
|
+
printf("%4d: +%d %s\n", i, cb.timestamp.to_i, cb.command)
|
134
|
+
i += 1
|
135
|
+
end
|
136
|
+
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
|
140
|
+
# TODO: need to add Shell#dump method
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def exec(command)
|
145
|
+
raise ArgumentError, 'nil command' if command.nil?
|
146
|
+
raise ArgumentError, 'invalid command class' if command.class != String
|
147
|
+
raise ArgumentError, 'empty command' if command.empty?
|
148
|
+
|
149
|
+
cmd_ary = command.split(/[ \t]/)
|
150
|
+
|
151
|
+
cmd = cmd_ary[0]
|
152
|
+
args = cmd_ary[1..-1]
|
153
|
+
|
154
|
+
send(@process, cmd, args)
|
155
|
+
end
|
156
|
+
|
157
|
+
DefaultPrompt = ':'
|
158
|
+
|
159
|
+
@banner
|
160
|
+
@process
|
161
|
+
@commands
|
162
|
+
@prompt
|
163
|
+
@history
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# timestamp.rb
|
4
|
+
# yesmar@speakeasy.net
|
5
|
+
|
6
|
+
module RCL
|
7
|
+
class Timestamp
|
8
|
+
attr_reader :create, :modify, :access
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@create = Time.now
|
12
|
+
@modify = nil
|
13
|
+
@access = nil
|
14
|
+
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_modify
|
19
|
+
@modify = Time.now
|
20
|
+
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_access
|
25
|
+
@access = Time.now
|
26
|
+
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
update_modify
|
32
|
+
update_access
|
33
|
+
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def dump(indent=0, stream=STDOUT)
|
38
|
+
raise ArgumentError, 'nil indent' if indent.nil?
|
39
|
+
raise ArgumentError, 'invalid indent class' if indent.class != Fixnum
|
40
|
+
raise ArgumentError, 'indent range error' if indent < 0
|
41
|
+
raise ArgumentError, 'nil stream' if stream.nil?
|
42
|
+
raise ArgumentError, 'invalid stream class' if stream.class != IO
|
43
|
+
|
44
|
+
# instance
|
45
|
+
indent.times { stream << ' ' }
|
46
|
+
stream << "#{self.class}<#{self.object_id}> instance:\n"
|
47
|
+
|
48
|
+
indent += 2
|
49
|
+
|
50
|
+
# create
|
51
|
+
indent.times { stream << ' ' }
|
52
|
+
stream << "create: #{@create}\n"
|
53
|
+
|
54
|
+
# modify
|
55
|
+
indent.times { stream << ' ' }
|
56
|
+
stream << "modify: #{!@modify.nil? ? @modify : '<unset>'}\n"
|
57
|
+
|
58
|
+
# access
|
59
|
+
indent.times { stream << ' ' }
|
60
|
+
stream << "access: #{!@access.nil? ? @access : '<unset>'}\n"
|
61
|
+
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
@create
|
68
|
+
@modify
|
69
|
+
@access
|
70
|
+
end
|
71
|
+
|
72
|
+
# convert milliseconds to hours, minutes, and seconds
|
73
|
+
def self.ms_to_s(ms)
|
74
|
+
raise ArgumentError, 'nil ms' if ms.nil?
|
75
|
+
raise ArgumentError, 'invalid ms class' if !ms.is_a?(Integer)
|
76
|
+
|
77
|
+
s = ms % 60
|
78
|
+
m = (ms / 60) % 60
|
79
|
+
h = (ms / 3600) % 24
|
80
|
+
|
81
|
+
str = []
|
82
|
+
|
83
|
+
str << h.to_s << 'h ' if h >= 1
|
84
|
+
str << m.to_s << 'm ' if m >= 1
|
85
|
+
str << s.to_s << 's ' if s > 0
|
86
|
+
|
87
|
+
return str.join
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
data/lib/rcl/token.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# token.rb
|
4
|
+
# yesmar@speakeasy.net
|
5
|
+
|
6
|
+
require 'digest/sha2'
|
7
|
+
|
8
|
+
module RCL
|
9
|
+
class Token
|
10
|
+
def initialize(key)
|
11
|
+
raise ArgumentError, 'nil key' if key.nil?
|
12
|
+
raise ArgumentError, 'invalid key class' if key.class != String
|
13
|
+
raise ArgumentError, 'empty key' if key.empty?
|
14
|
+
|
15
|
+
srand
|
16
|
+
|
17
|
+
@salt = [Array.new(6) { rand(256).chr }.join].pack("m").chomp
|
18
|
+
@hash = Digest::SHA256.hexdigest(@salt+key)
|
19
|
+
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def authenticate(key)
|
24
|
+
raise ArgumentError, 'nil key' if key.nil?
|
25
|
+
raise ArgumentError, 'invalid key class' if key.class != String
|
26
|
+
raise ArgumentError, 'empty key' if key.empty?
|
27
|
+
|
28
|
+
Digest::SHA256.hexdigest(@salt+key) == @hash
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
@salt
|
34
|
+
@hash
|
35
|
+
end
|
36
|
+
end
|
data/lib/rcl/url.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# url.rb
|
4
|
+
# yesmar@speakeasy.net
|
5
|
+
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module RCL
|
9
|
+
module URL
|
10
|
+
def self.encode(url)
|
11
|
+
raise ArgumentError, 'nil url' if url.nil?
|
12
|
+
raise ArgumentError, 'invalid url' if url.class != String
|
13
|
+
raise ArgumentError, 'empty url' if url.empty?
|
14
|
+
|
15
|
+
URI::escape(url, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.decode(url)
|
19
|
+
raise ArgumentError, 'nil url' if url.nil?
|
20
|
+
raise ArgumentError, 'invalid url' if url.class != String
|
21
|
+
raise ArgumentError, 'empty url' if url.empty?
|
22
|
+
|
23
|
+
URI::unescape(url)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.encoded?(url)
|
27
|
+
raise ArgumentError, 'nil url' if url.nil?
|
28
|
+
raise ArgumentError, 'invalid url' if url.class != String
|
29
|
+
raise ArgumentError, 'empty url' if url.empty?
|
30
|
+
|
31
|
+
return (url =~ /%/) ? true : false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
data/lib/rcl/xml.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# xml.rb
|
4
|
+
# yesmar@speakeasy.net
|
5
|
+
|
6
|
+
require 'rexml/document'
|
7
|
+
require 'rexml/validation/relaxng'
|
8
|
+
|
9
|
+
require 'perms'
|
10
|
+
|
11
|
+
module RCL
|
12
|
+
module XML
|
13
|
+
# remove leading and trailing whitespace from elements
|
14
|
+
def self.preprocess(pathname)
|
15
|
+
Perms::check_file_r(pathname)
|
16
|
+
|
17
|
+
doc = IO.readlines(pathname)
|
18
|
+
|
19
|
+
doc.each do |line|
|
20
|
+
line.gsub!(/\s+</, '<')
|
21
|
+
line.gsub!(/\s+$/, '')
|
22
|
+
end
|
23
|
+
|
24
|
+
doc.join
|
25
|
+
end
|
26
|
+
|
27
|
+
# validate XML document against specified RELAXNG schema
|
28
|
+
def self.validate(pathname, schema_pathname=nil)
|
29
|
+
Perms::check_file_r(pathname)
|
30
|
+
|
31
|
+
if schema_pathname.nil?
|
32
|
+
schema_pathname = \
|
33
|
+
"#{File.basename(pathname, File.extname(pathname))}.xsd"
|
34
|
+
end
|
35
|
+
|
36
|
+
Perms::check_file_r(schema_pathname)
|
37
|
+
|
38
|
+
begin
|
39
|
+
schema = File.new(schema_pathname)
|
40
|
+
validator = REXML::Validation::RelaxNG.new(schema)
|
41
|
+
parser = REXML::Parsers::TreeParser.new(preprocess(pathname))
|
42
|
+
parser.add_listener(validator.reset)
|
43
|
+
parser.parse
|
44
|
+
rescue REXML::Validation::ValidationException => e
|
45
|
+
raise "#{e}"
|
46
|
+
rescue Exception => e
|
47
|
+
raise "#{e}"
|
48
|
+
end
|
49
|
+
|
50
|
+
true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rcl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ramsey Dow
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-02-27 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: yesmar @nospam@ speakeasy.net
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- lib/rcl.rb
|
26
|
+
- lib/rcl/base.rb
|
27
|
+
- lib/rcl/perms.rb
|
28
|
+
- lib/rcl/shell.rb
|
29
|
+
- lib/rcl/timestamp.rb
|
30
|
+
- lib/rcl/token.rb
|
31
|
+
- lib/rcl/url.rb
|
32
|
+
- lib/rcl/xml.rb
|
33
|
+
- README
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: http://rcl.rubyforge.org/
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project: http://rubyforge.org/projects/rcl/
|
56
|
+
rubygems_version: 1.0.1
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: Ramsey's Common Library
|
60
|
+
test_files: []
|
61
|
+
|