ontomde-core 1.0.2 → 1.0.4
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/History.txt +10 -5
- data/Manifest.txt +1 -2
- data/Manual.txt +88 -0
- data/README.txt +79 -48
- data/Rakefile +4 -3
- data/lib/ontomde-core/bootstrap_rdfs.rb +36 -37
- data/lib/ontomde-core/clone.rb +72 -73
- data/lib/ontomde-core/context.rb +114 -115
- data/lib/ontomde-core/customERB.rb +72 -72
- data/lib/ontomde-core/custom_method_missing.rb +52 -53
- data/lib/ontomde-core/delayed.rb +9 -9
- data/lib/ontomde-core/demoInstaller.rb +25 -25
- data/lib/ontomde-core/exceptions.rb +27 -28
- data/lib/ontomde-core/fileLoader.rb +191 -163
- data/lib/ontomde-core/fileTypes.rb +145 -133
- data/lib/ontomde-core/helper.rb +547 -538
- data/lib/ontomde-core/log.rb +32 -32
- data/lib/ontomde-core/meta.rb +410 -316
- data/lib/ontomde-core/profil.rb +60 -62
- data/lib/ontomde-core/resource.rb +277 -272
- data/lib/ontomde-core/resourceSet.rb +185 -173
- data/lib/ontomde-core/triplet.rb +159 -161
- data/lib/ontomde-core/version.rb +5 -5
- data/lib/ontomde-core.rb +26 -35
- data/test/protege/etatCivil.pprj +779 -526
- data/test/protege/etatCivil.rdf +3 -1
- data/test/protege/etatCivil.rdfs +6 -0
- data/test/protege/test_demo.rb +68 -46
- data/test/test_context.rb +88 -88
- data/test/test_ontomde-core.rb +9 -9
- data/test/test_protected.rb +291 -238
- data/test/test_uri.rb +37 -37
- data/test/unit_test_crash.rb +22 -22
- metadata +66 -59
- data/bin/ontomde-core +0 -0
- data/lib/ontomde-core/loader.rb +0 -70
data/lib/ontomde-core/context.rb
CHANGED
@@ -1,115 +1,114 @@
|
|
1
|
-
# Context management
|
2
|
-
|
3
|
-
|
4
|
-
require '
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
#
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
1
|
+
# Context management
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
#require 'ontomde-core/exceptions.rb'
|
5
|
+
|
6
|
+
#Internal use.
|
7
|
+
#
|
8
|
+
#Used for storing context.
|
9
|
+
class WarningHash < Hash
|
10
|
+
|
11
|
+
#Returns context value associated to key.
|
12
|
+
#Raises an error if key is not found.
|
13
|
+
# Returns default, when context is undefined for key, and a default value is provided.
|
14
|
+
def [](key,default=Object.class)
|
15
|
+
val=super(key)
|
16
|
+
return val unless val.nil?
|
17
|
+
#Note: Object.class is used as a magic number.
|
18
|
+
return default unless default==Object.class
|
19
|
+
raise Warning.new(), <<FINCODE
|
20
|
+
Evaluation interrompue:
|
21
|
+
La session ne contient pas la variable :#{key}.
|
22
|
+
L'exemple de code suivant permet de definir une variable de contexte:
|
23
|
+
|
24
|
+
votre code
|
25
|
+
mtk_context(:#{key}=>'valeur'){
|
26
|
+
votre code
|
27
|
+
puts context[:#{key}]
|
28
|
+
votre code
|
29
|
+
}
|
30
|
+
FINCODE
|
31
|
+
end
|
32
|
+
def get(key)
|
33
|
+
return self[key] if self.include?(key)
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Mrdf_Model
|
39
|
+
@@context=WarningHash.new()
|
40
|
+
|
41
|
+
def context
|
42
|
+
return @@context
|
43
|
+
end
|
44
|
+
|
45
|
+
# Similar to mtk_context but preserves already defined context.
|
46
|
+
# Used to provide a default context.
|
47
|
+
def mtk_default_context(*additional_context,&block)
|
48
|
+
filtered_context=Array.new
|
49
|
+
additional_context.each { |item| item.each { |k,v|
|
50
|
+
next if @@context.include?(k)
|
51
|
+
filtered_context << item
|
52
|
+
}}
|
53
|
+
mtk_context(*filtered_context,&block)
|
54
|
+
end
|
55
|
+
|
56
|
+
#Defines context variables for use in block passed as parameter.
|
57
|
+
#Existing context variable are redefined. (cf. mtk_default_context )
|
58
|
+
#When exiting block, previously defined context variables are restored.
|
59
|
+
#
|
60
|
+
#Example 1:
|
61
|
+
# mtk_context( :build => "build\", :option => true) {
|
62
|
+
# your-code
|
63
|
+
# puts context[:build]
|
64
|
+
# your-code
|
65
|
+
# puts context[:option]
|
66
|
+
# your-code
|
67
|
+
# }
|
68
|
+
#
|
69
|
+
#Example 2:
|
70
|
+
# mtk_context( :build => "BUILD_ONE\") {
|
71
|
+
# your-code
|
72
|
+
# puts context[:build] # BUILD_ONE
|
73
|
+
# mtk_context( :build => "NEW_DIR", :option => true) {
|
74
|
+
# your-code
|
75
|
+
# puts context[:build] # NEW_DIR\
|
76
|
+
# your-code
|
77
|
+
# puts context[:option]
|
78
|
+
# your-code
|
79
|
+
# }
|
80
|
+
# puts context[:build] # BUILD_ONE
|
81
|
+
# }
|
82
|
+
def mtk_context(*additional_context,&block)
|
83
|
+
context_save=@@context
|
84
|
+
@@context=context_save.clone
|
85
|
+
additional_context.each { |item| item.each { |k,v|
|
86
|
+
@@context[k]=v
|
87
|
+
}}
|
88
|
+
yield
|
89
|
+
@@context=context_save
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
module Mrdf_Resource
|
96
|
+
|
97
|
+
# returns current context
|
98
|
+
def context
|
99
|
+
return @rdf_model.context
|
100
|
+
end
|
101
|
+
|
102
|
+
# cf: Mrdf_Model::mtk_context
|
103
|
+
def mtk_context(*args,&block)
|
104
|
+
return @rdf_model.mtk_context(*args,&block)
|
105
|
+
end
|
106
|
+
#
|
107
|
+
# cf: Mrdf_Model::mtk_default_context
|
108
|
+
def mtk_default_context(*args,&block)
|
109
|
+
return @rdf_model.mtk_default_context(*args,&block)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
|
@@ -1,14 +1,14 @@
|
|
1
1
|
|
2
2
|
class Crdf_Ressource
|
3
|
-
def loadTPL(name)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
3
|
+
def loadTPL(name)
|
4
|
+
tpl=""
|
5
|
+
File.open(name) { |f|
|
6
|
+
f.each { |l|
|
7
|
+
tpl=tpl+l
|
8
|
+
}
|
9
|
+
}
|
10
|
+
return CustomERB.new(tpl)
|
11
|
+
end
|
12
12
|
end
|
13
13
|
|
14
14
|
|
@@ -35,7 +35,7 @@ end
|
|
35
35
|
# purposes of generating document information details and/or flow control.
|
36
36
|
#
|
37
37
|
# A very simple example is this:
|
38
|
-
#
|
38
|
+
#
|
39
39
|
# require 'erb'
|
40
40
|
#
|
41
41
|
# x = 42
|
@@ -83,39 +83,39 @@ end
|
|
83
83
|
# <tt>@q{...}</tt> to avoid trouble with the backslash.
|
84
84
|
#
|
85
85
|
# require "erb"
|
86
|
-
#
|
86
|
+
#
|
87
87
|
# # Create template.
|
88
88
|
# template = @q{
|
89
89
|
# From: James Edward Gray II <james@grayproductions.net>
|
90
90
|
# To: <@= to @>
|
91
91
|
# Subject: Addressing Needs
|
92
|
-
#
|
92
|
+
#
|
93
93
|
# <@= to[/\w+/] @>:
|
94
|
-
#
|
94
|
+
#
|
95
95
|
# Just wanted to send a quick note assuring that your needs are being
|
96
96
|
# addressed.
|
97
|
-
#
|
97
|
+
#
|
98
98
|
# I want you to know that my team will keep working on the issues,
|
99
99
|
# especially:
|
100
|
-
#
|
100
|
+
#
|
101
101
|
# <@# ignore numerous minor requests -- focus on priorities @>
|
102
102
|
# @ priorities.each do |priority|
|
103
103
|
# * <@= priority @>
|
104
104
|
# @ end
|
105
|
-
#
|
105
|
+
#
|
106
106
|
# Thanks for your patience.
|
107
|
-
#
|
107
|
+
#
|
108
108
|
# James Edward Gray II
|
109
109
|
# }.gsub(/^ /, '')
|
110
|
-
#
|
110
|
+
#
|
111
111
|
# message = CustomERB.new(template, 0, "@<>")
|
112
|
-
#
|
112
|
+
#
|
113
113
|
# # Set up template data.
|
114
114
|
# to = "Community Spokesman <spokesman@ruby_community.org>"
|
115
115
|
# priorities = [ "Run Ruby Quiz",
|
116
116
|
# "Document Modules",
|
117
117
|
# "Answer Questions on Ruby Talk" ]
|
118
|
-
#
|
118
|
+
#
|
119
119
|
# # Produce result.
|
120
120
|
# email = message.result
|
121
121
|
# puts email
|
@@ -125,19 +125,19 @@ end
|
|
125
125
|
# From: James Edward Gray II <james@grayproductions.net>
|
126
126
|
# To: Community Spokesman <spokesman@ruby_community.org>
|
127
127
|
# Subject: Addressing Needs
|
128
|
-
#
|
128
|
+
#
|
129
129
|
# Community:
|
130
|
-
#
|
130
|
+
#
|
131
131
|
# Just wanted to send a quick note assuring that your needs are being addressed.
|
132
|
-
#
|
132
|
+
#
|
133
133
|
# I want you to know that my team will keep working on the issues, especially:
|
134
|
-
#
|
134
|
+
#
|
135
135
|
# * Run Ruby Quiz
|
136
136
|
# * Document Modules
|
137
137
|
# * Answer Questions on Ruby Talk
|
138
|
-
#
|
138
|
+
#
|
139
139
|
# Thanks for your patience.
|
140
|
-
#
|
140
|
+
#
|
141
141
|
# James Edward Gray II
|
142
142
|
#
|
143
143
|
# === Ruby in HTML
|
@@ -147,7 +147,7 @@ end
|
|
147
147
|
# variables in the Product object can be resolved.
|
148
148
|
#
|
149
149
|
# require "erb"
|
150
|
-
#
|
150
|
+
#
|
151
151
|
# # Build template data class.
|
152
152
|
# class Product
|
153
153
|
# def initialize( code, name, desc, cost )
|
@@ -155,37 +155,37 @@ end
|
|
155
155
|
# @name = name
|
156
156
|
# @desc = desc
|
157
157
|
# @cost = cost
|
158
|
-
#
|
158
|
+
#
|
159
159
|
# @features = [ ]
|
160
160
|
# end
|
161
|
-
#
|
161
|
+
#
|
162
162
|
# def add_feature( feature )
|
163
163
|
# @features << feature
|
164
164
|
# end
|
165
|
-
#
|
165
|
+
#
|
166
166
|
# # Support templating of member data.
|
167
167
|
# def get_binding
|
168
168
|
# binding
|
169
169
|
# end
|
170
|
-
#
|
170
|
+
#
|
171
171
|
# # ...
|
172
172
|
# end
|
173
|
-
#
|
173
|
+
#
|
174
174
|
# # Create template.
|
175
175
|
# template = @{
|
176
176
|
# <html>
|
177
177
|
# <head><title>Ruby Toys -- <@= @name @></title></head>
|
178
178
|
# <body>
|
179
|
-
#
|
179
|
+
#
|
180
180
|
# <h1><@= @name @> (<@= @code @>)</h1>
|
181
181
|
# <p><@= @desc @></p>
|
182
|
-
#
|
182
|
+
#
|
183
183
|
# <ul>
|
184
184
|
# <@ @features.each do |f| @>
|
185
185
|
# <li><b><@= f @></b></li>
|
186
186
|
# <@ end @>
|
187
187
|
# </ul>
|
188
|
-
#
|
188
|
+
#
|
189
189
|
# <p>
|
190
190
|
# <@ if @cost < 10 @>
|
191
191
|
# <b>Only <@= @cost @>!!!</b>
|
@@ -193,13 +193,13 @@ end
|
|
193
193
|
# Call for a price, today!
|
194
194
|
# <@ end @>
|
195
195
|
# </p>
|
196
|
-
#
|
196
|
+
#
|
197
197
|
# </body>
|
198
198
|
# </html>
|
199
199
|
# }.gsub(/^ /, '')
|
200
|
-
#
|
200
|
+
#
|
201
201
|
# rhtml = CustomERB.new(template)
|
202
|
-
#
|
202
|
+
#
|
203
203
|
# # Set up template data.
|
204
204
|
# toy = Product.new( "TZ-1002",
|
205
205
|
# "Rubysapien",
|
@@ -210,7 +210,7 @@ end
|
|
210
210
|
# toy.add_feature("Karate-Chop Action!!!")
|
211
211
|
# toy.add_feature("Matz signature on left leg.")
|
212
212
|
# toy.add_feature("Gem studded eyes... Rubies, of course!")
|
213
|
-
#
|
213
|
+
#
|
214
214
|
# # Produce result.
|
215
215
|
# rhtml.run(toy.get_binding)
|
216
216
|
#
|
@@ -219,10 +219,10 @@ end
|
|
219
219
|
# <html>
|
220
220
|
# <head><title>Ruby Toys -- Rubysapien</title></head>
|
221
221
|
# <body>
|
222
|
-
#
|
222
|
+
#
|
223
223
|
# <h1>Rubysapien (TZ-1002)</h1>
|
224
224
|
# <p>Geek's Best Friend! Responds to Ruby commands...</p>
|
225
|
-
#
|
225
|
+
#
|
226
226
|
# <ul>
|
227
227
|
# <li><b>Listens for verbal commands in the Ruby language!</b></li>
|
228
228
|
# <li><b>Ignores Perl, Java, and all C variants.</b></li>
|
@@ -230,15 +230,15 @@ end
|
|
230
230
|
# <li><b>Matz signature on left leg.</b></li>
|
231
231
|
# <li><b>Gem studded eyes... Rubies, of course!</b></li>
|
232
232
|
# </ul>
|
233
|
-
#
|
233
|
+
#
|
234
234
|
# <p>
|
235
235
|
# Call for a price, today!
|
236
236
|
# </p>
|
237
|
-
#
|
237
|
+
#
|
238
238
|
# </body>
|
239
239
|
# </html>
|
240
240
|
#
|
241
|
-
#
|
241
|
+
#
|
242
242
|
# == Notes
|
243
243
|
#
|
244
244
|
# There are a variety of templating solutions available in various Ruby projects:
|
@@ -315,7 +315,7 @@ class CustomERB
|
|
315
315
|
end
|
316
316
|
end
|
317
317
|
attr_accessor :stag
|
318
|
-
|
318
|
+
|
319
319
|
def scan(&block)
|
320
320
|
@stag = nil
|
321
321
|
if @percent
|
@@ -415,7 +415,7 @@ class CustomERB
|
|
415
415
|
end
|
416
416
|
end
|
417
417
|
end
|
418
|
-
|
418
|
+
|
419
419
|
Scanner.regist_scanner(SimpleScanner, nil, false)
|
420
420
|
|
421
421
|
begin
|
@@ -514,13 +514,13 @@ class CustomERB
|
|
514
514
|
def push(cmd)
|
515
515
|
@line << cmd
|
516
516
|
end
|
517
|
-
|
517
|
+
|
518
518
|
def cr
|
519
519
|
@script << (@line.join('; '))
|
520
520
|
@line = []
|
521
521
|
@script << "\n"
|
522
522
|
end
|
523
|
-
|
523
|
+
|
524
524
|
def close
|
525
525
|
return unless @line
|
526
526
|
@compiler.post_cmd.each do |x|
|
@@ -636,19 +636,19 @@ end
|
|
636
636
|
class CustomERB
|
637
637
|
#
|
638
638
|
# Constructs a new CustomERB object with the template specified in _str_.
|
639
|
-
#
|
639
|
+
#
|
640
640
|
# An CustomERB object works by building a chunk of Ruby code that will output
|
641
641
|
# the completed template when run. If _safe_level_ is set to a non-nil value,
|
642
642
|
# CustomERB code will be run in a separate thread with <b>$SAFE</b> set to the
|
643
643
|
# provided level.
|
644
|
-
#
|
644
|
+
#
|
645
645
|
# If _trim_mode_ is passed a String containing one or more of the following
|
646
646
|
# modifiers, CustomERB will adjust its code generation as listed:
|
647
|
-
#
|
647
|
+
#
|
648
648
|
# @ enables Ruby code processing for lines beginning with @
|
649
649
|
# <> omit newline for lines starting with <@ and ending in @>
|
650
650
|
# > omit newline for lines ending in @>
|
651
|
-
#
|
651
|
+
#
|
652
652
|
# _eoutvar_ can be used to set the name of the variable CustomERB will build up
|
653
653
|
# its output in. This is useful when you need to run multiple CustomERB
|
654
654
|
# templates through the same binding and/or when you want to control where
|
@@ -657,20 +657,20 @@ class CustomERB
|
|
657
657
|
# === Example
|
658
658
|
#
|
659
659
|
# require "erb"
|
660
|
-
#
|
660
|
+
#
|
661
661
|
# # build data class
|
662
662
|
# class Listings
|
663
663
|
# PRODUCT = { :name => "Chicken Fried Steak",
|
664
664
|
# :desc => "A well messages pattie, breaded and fried.",
|
665
665
|
# :cost => 9.95 }
|
666
|
-
#
|
666
|
+
#
|
667
667
|
# attr_reader :product, :price
|
668
|
-
#
|
668
|
+
#
|
669
669
|
# def initialize( product = "", price = "" )
|
670
670
|
# @product = product
|
671
671
|
# @price = price
|
672
672
|
# end
|
673
|
-
#
|
673
|
+
#
|
674
674
|
# def build
|
675
675
|
# b = binding
|
676
676
|
# # create and run templates, filling member data variebles
|
@@ -684,21 +684,21 @@ class CustomERB
|
|
684
684
|
# END_PRICE
|
685
685
|
# end
|
686
686
|
# end
|
687
|
-
#
|
687
|
+
#
|
688
688
|
# # setup template data
|
689
689
|
# listings = Listings.new
|
690
690
|
# listings.build
|
691
|
-
#
|
691
|
+
#
|
692
692
|
# puts listings.product + "\n" + listings.price
|
693
693
|
#
|
694
694
|
# _Generates_
|
695
695
|
#
|
696
696
|
# Chicken Fried Steak
|
697
697
|
# A well messages pattie, breaded and fried.
|
698
|
-
#
|
698
|
+
#
|
699
699
|
# Chicken Fried Steak -- 9.95
|
700
700
|
# A well messages pattie, breaded and fried.
|
701
|
-
#
|
701
|
+
#
|
702
702
|
def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
|
703
703
|
@safe_level = safe_level
|
704
704
|
compiler = CustomERB::Compiler.new(trim_mode)
|
@@ -725,7 +725,7 @@ class CustomERB
|
|
725
725
|
|
726
726
|
cmd = []
|
727
727
|
cmd.push "#{eoutvar} = ''"
|
728
|
-
|
728
|
+
|
729
729
|
compiler.pre_cmd = cmd
|
730
730
|
|
731
731
|
cmd = []
|
@@ -743,13 +743,13 @@ class CustomERB
|
|
743
743
|
# Executes the generated CustomERB code to produce a completed template, returning
|
744
744
|
# the results of that code. (See CustomERB#new for details on how this process can
|
745
745
|
# be affected by _safe_level_.)
|
746
|
-
#
|
746
|
+
#
|
747
747
|
# _b_ accepts a Binding or Proc object which is used to set the context of
|
748
748
|
# code evaluation.
|
749
749
|
#
|
750
750
|
def result(b=TOPLEVEL_BINDING)
|
751
751
|
if @safe_level
|
752
|
-
th = Thread.start {
|
752
|
+
th = Thread.start {
|
753
753
|
$SAFE = @safe_level
|
754
754
|
eval(@src, b, (@filename || '(erb)'), 1)
|
755
755
|
}
|
@@ -784,14 +784,14 @@ class CustomERB
|
|
784
784
|
public
|
785
785
|
#
|
786
786
|
# A utility method for escaping HTML tag characters in _s_.
|
787
|
-
#
|
787
|
+
#
|
788
788
|
# require "erb"
|
789
789
|
# include CustomERB::Util
|
790
|
-
#
|
790
|
+
#
|
791
791
|
# puts html_escape("is a > 0 & a < 10?")
|
792
|
-
#
|
792
|
+
#
|
793
793
|
# _Generates_
|
794
|
-
#
|
794
|
+
#
|
795
795
|
# is a > 0 & a < 10?
|
796
796
|
#
|
797
797
|
def html_escape(s)
|
@@ -800,17 +800,17 @@ class CustomERB
|
|
800
800
|
alias h html_escape
|
801
801
|
module_function :h
|
802
802
|
module_function :html_escape
|
803
|
-
|
803
|
+
|
804
804
|
#
|
805
805
|
# A utility method for encoding the String _s_ as a URL.
|
806
|
-
#
|
806
|
+
#
|
807
807
|
# require "erb"
|
808
808
|
# include CustomERB::Util
|
809
|
-
#
|
809
|
+
#
|
810
810
|
# puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
|
811
|
-
#
|
811
|
+
#
|
812
812
|
# _Generates_
|
813
|
-
#
|
813
|
+
#
|
814
814
|
# Programming@20Ruby@3A@20@20The@20Pragmatic@20Programmer@27s@20Guide
|
815
815
|
#
|
816
816
|
def url_encode(s)
|