ontomde-core 1.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/History.txt +5 -0
- data/Manifest.txt +37 -0
- data/README.txt +48 -0
- data/Rakefile +19 -0
- data/bin/ontomde-core +0 -0
- data/lib/ontomde-core.rb +35 -0
- data/lib/ontomde-core/bootstrap_rdfs.rb +37 -0
- data/lib/ontomde-core/clone.rb +73 -0
- data/lib/ontomde-core/context.rb +115 -0
- data/lib/ontomde-core/customERB.rb +842 -0
- data/lib/ontomde-core/custom_method_missing.rb +53 -0
- data/lib/ontomde-core/delayed.rb +20 -0
- data/lib/ontomde-core/demoInstaller.rb +32 -0
- data/lib/ontomde-core/exceptions.rb +28 -0
- data/lib/ontomde-core/fileLoader.rb +163 -0
- data/lib/ontomde-core/fileTypes.rb +133 -0
- data/lib/ontomde-core/helper.rb +538 -0
- data/lib/ontomde-core/loader.rb +70 -0
- data/lib/ontomde-core/log.rb +32 -0
- data/lib/ontomde-core/meta.rb +316 -0
- data/lib/ontomde-core/profil.rb +62 -0
- data/lib/ontomde-core/resource.rb +272 -0
- data/lib/ontomde-core/resourceSet.rb +173 -0
- data/lib/ontomde-core/triplet.rb +161 -0
- data/lib/ontomde-core/version.rb +5 -0
- data/test/protege/demo.sh +2 -0
- data/test/protege/etatCivil.pprj +891 -0
- data/test/protege/etatCivil.rdf +29 -0
- data/test/protege/etatCivil.rdfs +71 -0
- data/test/protege/test_demo.rb +46 -0
- data/test/test_context.rb +88 -0
- data/test/test_ontomde-core.rb +9 -0
- data/test/test_protected.rb +352 -0
- data/test/test_uri.rb +37 -0
- data/test/unit_test_crash.rb +22 -0
- data/test/unit_test_protected_sample +27 -0
- data/test/unit_test_protected_wrongEnd +9 -0
- metadata +106 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/ontomde-core
|
6
|
+
lib/ontomde-core.rb
|
7
|
+
lib/ontomde-core/version.rb
|
8
|
+
lib/ontomde-core/context.rb
|
9
|
+
lib/ontomde-core/loader.rb
|
10
|
+
lib/ontomde-core/bootstrap_rdfs.rb
|
11
|
+
lib/ontomde-core/delayed.rb
|
12
|
+
lib/ontomde-core/profil.rb
|
13
|
+
lib/ontomde-core/resource.rb
|
14
|
+
lib/ontomde-core/helper.rb
|
15
|
+
lib/ontomde-core/meta.rb
|
16
|
+
lib/ontomde-core/exceptions.rb
|
17
|
+
lib/ontomde-core/demoInstaller.rb
|
18
|
+
lib/ontomde-core/customERB.rb
|
19
|
+
lib/ontomde-core/triplet.rb
|
20
|
+
lib/ontomde-core/log.rb
|
21
|
+
lib/ontomde-core/fileTypes.rb
|
22
|
+
lib/ontomde-core/fileLoader.rb
|
23
|
+
lib/ontomde-core/custom_method_missing.rb
|
24
|
+
lib/ontomde-core/resourceSet.rb
|
25
|
+
lib/ontomde-core/clone.rb
|
26
|
+
test/test_uri.rb
|
27
|
+
test/test_ontomde-core.rb
|
28
|
+
test/protege/etatCivil.rdfs
|
29
|
+
test/protege/etatCivil.rdf
|
30
|
+
test/protege/test_demo.rb
|
31
|
+
test/protege/demo.sh
|
32
|
+
test/protege/etatCivil.pprj
|
33
|
+
test/test_protected.rb
|
34
|
+
test/unit_test_protected_sample
|
35
|
+
test/unit_test_crash.rb
|
36
|
+
test/test_context.rb
|
37
|
+
test/unit_test_protected_wrongEnd
|
data/README.txt
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
ontomde-core
|
2
|
+
by FIX (your name)
|
3
|
+
FIX (url)
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
FIX (describe your package)
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* FIX (list of features or problems)
|
12
|
+
|
13
|
+
== SYNOPSIS:
|
14
|
+
|
15
|
+
FIX (code sample of usage)
|
16
|
+
|
17
|
+
== REQUIREMENTS:
|
18
|
+
|
19
|
+
* FIX (list of requirements)
|
20
|
+
|
21
|
+
== INSTALL:
|
22
|
+
|
23
|
+
* FIX (sudo gem install, anything else)
|
24
|
+
|
25
|
+
== LICENSE:
|
26
|
+
|
27
|
+
(The MIT License)
|
28
|
+
|
29
|
+
Copyright (c) 2007 FIX
|
30
|
+
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
32
|
+
a copy of this software and associated documentation files (the
|
33
|
+
'Software'), to deal in the Software without restriction, including
|
34
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
35
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
36
|
+
permit persons to whom the Software is furnished to do so, subject to
|
37
|
+
the following conditions:
|
38
|
+
|
39
|
+
The above copyright notice and this permission notice shall be
|
40
|
+
included in all copies or substantial portions of the Software.
|
41
|
+
|
42
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
43
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
44
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
45
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
46
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
47
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
48
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/ontomde-core/version.rb'
|
6
|
+
|
7
|
+
Hoe.new('ontomde-core', Ontomde::Core::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'ontomde'
|
9
|
+
p.author = 'Stephane (Pierre) Carrie'
|
10
|
+
p.email = 'stephanepierre.carrie@orange-ftgroup.com'
|
11
|
+
p.summary = 'OntoMDE core cartridge (RDF/RDFS handling,helpers)'
|
12
|
+
# p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
13
|
+
# p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
14
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
|
+
p.spec_extras[:required_ruby_version] = '>= 1.8.4'
|
16
|
+
p.extra_deps=[ ['ontomde-redland-win','= 1.0.3'] ]
|
17
|
+
end
|
18
|
+
|
19
|
+
# vim: syntax=Ruby
|
data/bin/ontomde-core
ADDED
File without changes
|
data/lib/ontomde-core.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# In order to use ontomde-core just include this file
|
2
|
+
#
|
3
|
+
# include 'ontomde-core'
|
4
|
+
#
|
5
|
+
# NOTE: cf demo/etatCivil for sample raw use of ontomde-core.
|
6
|
+
#
|
7
|
+
#:include: shared/license.rdoc
|
8
|
+
|
9
|
+
require "#{__FILE__[0..-4]}/version.rb"
|
10
|
+
|
11
|
+
require 'set'
|
12
|
+
require 'ontomde-redland-win'
|
13
|
+
|
14
|
+
here="#{File.dirname(__FILE__)}/ontomde-core"
|
15
|
+
|
16
|
+
require "#{here}/log.rb"
|
17
|
+
require "#{here}/fileLoader.rb"
|
18
|
+
require "#{here}/custom_method_missing"
|
19
|
+
require "#{here}/triplet.rb"
|
20
|
+
require "#{here}/exceptions.rb"
|
21
|
+
require "#{here}/meta.rb"
|
22
|
+
require "#{here}/resource.rb"
|
23
|
+
require "#{here}/resourceSet.rb"
|
24
|
+
require "#{here}/bootstrap_rdfs.rb"
|
25
|
+
require "#{here}/clone.rb"
|
26
|
+
require "#{here}/fileTypes.rb"
|
27
|
+
require "#{here}/helper.rb"
|
28
|
+
require "#{here}/context.rb"
|
29
|
+
require "#{here}/delayed.rb"
|
30
|
+
|
31
|
+
#MTKRunner.rb
|
32
|
+
require "#{here}/loader.rb"
|
33
|
+
#require "#{here}/profil.rb"
|
34
|
+
require "#{here}/customERB.rb"
|
35
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Bootstrap of rdfs metamodel
|
2
|
+
#:include: ../shared/license.rdoc
|
3
|
+
|
4
|
+
module Mrdfs_Resource
|
5
|
+
end
|
6
|
+
|
7
|
+
module Mrdfs_Class
|
8
|
+
end
|
9
|
+
|
10
|
+
class Crdfs_Class < Crdf_Resource
|
11
|
+
include Mrdfs_Class
|
12
|
+
attr_reader :ClassGenerated
|
13
|
+
attr_writer :ClassGenerated
|
14
|
+
def initialize(model,uri)
|
15
|
+
super(model,uri)
|
16
|
+
@mtk_rubyClassGenerated=false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
module Mrdf_Property
|
20
|
+
end
|
21
|
+
|
22
|
+
class Crdf_Property < Crdf_Resource
|
23
|
+
include Mrdf_Property
|
24
|
+
attr_reader :rdfs_domain, :rdfs_range
|
25
|
+
attr_reader :sys_inverseProperty
|
26
|
+
@rdfs_domain=ArrayOrSingleElement.new()
|
27
|
+
#attr_writer :rdfs_domain, :rdfs_range
|
28
|
+
end
|
29
|
+
|
30
|
+
module Mrdfs_Literal
|
31
|
+
end
|
32
|
+
|
33
|
+
class Crdfs_Literal < Crdf_Resource
|
34
|
+
include Mrdfs_Literal
|
35
|
+
attr_reader :rdfs_domain, :rdfs_range
|
36
|
+
#attr_writer :rdfs_domain, :rdfs_range
|
37
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#Model transformation methods
|
2
|
+
#:include: ../shared/license.rdoc
|
3
|
+
|
4
|
+
class String
|
5
|
+
# Clones a string
|
6
|
+
# return self by default.(String are not cloned)
|
7
|
+
def rdfx_clone
|
8
|
+
return self
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Mrdf_Resource
|
13
|
+
# Clones a uml resource.
|
14
|
+
# Referenced objects are cloned if rdfx_copyOnClone says so.
|
15
|
+
def rdfx_clone
|
16
|
+
c=self.clone
|
17
|
+
c.rdf_uri="_transient_#{c.object_id}"
|
18
|
+
c.rdf_model[c.rdf_uri]=c
|
19
|
+
|
20
|
+
instance_variables.each { |v|
|
21
|
+
ivg=instance_variable_get(v)
|
22
|
+
next if (!ivg.kind_of?(ArrayOrSingleElement)) ||
|
23
|
+
(!isResetable?(v)) ||
|
24
|
+
(!rdfx_copyOnClone?(v))
|
25
|
+
|
26
|
+
newVal=createEmptyAttributeValue
|
27
|
+
#puts "clone v=#{v}"
|
28
|
+
self.instance_variable_get(v).each { | res|
|
29
|
+
newVal.push(res.rdfx_clone)
|
30
|
+
c.instance_variable_set(v,newVal)
|
31
|
+
}
|
32
|
+
}
|
33
|
+
return c
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns true if object should be copied on clone for this property.
|
37
|
+
# NOTE:
|
38
|
+
# returns true if property name contains "_owned". (works for UML)
|
39
|
+
def rdfx_copyOnClone?(prop)
|
40
|
+
return prop.include?('_owned')
|
41
|
+
#copyOrClone=copyOnCloneProperties[prop]
|
42
|
+
#if copyOrClone.nil?
|
43
|
+
#puts "WARNING: unspecified copy on clone for #{prop} on #{self.class.name}"
|
44
|
+
#end
|
45
|
+
#return copyOrClone
|
46
|
+
end
|
47
|
+
end
|
48
|
+
#module Mrdf_Resource
|
49
|
+
# #CopyOnCloneProperties={ }
|
50
|
+
# def copyOnCloneProperties
|
51
|
+
# #CopyOnCloneProperties
|
52
|
+
# end
|
53
|
+
#end
|
54
|
+
#module Muml_Class
|
55
|
+
# CopyOnCloneProperties={ '@uml_packageableElement_packageableElement_visibility' => true,
|
56
|
+
# '@uml_structuredClassifier_ownedAttribute' => true,
|
57
|
+
# '@mtk_rubyClassGenerated' => true,
|
58
|
+
# '@uml_classifier_generalization' => true,
|
59
|
+
# '@uml_namedElement_visibility' => true,
|
60
|
+
# '@uml_namedElement_clientDependency' => true,
|
61
|
+
# '@umlx_packageableElement_owner' => true,
|
62
|
+
# '@ext_isReferencedBy' => true,
|
63
|
+
# '@uml_class_ownedOperation' => true,
|
64
|
+
# '@uml_behavioredClassifier_implementation' => true,
|
65
|
+
# '@uml_namedElement_name' => true }
|
66
|
+
# #def copyOnCloneProperties
|
67
|
+
# # CopyOnCloneProperties #_class
|
68
|
+
# #end
|
69
|
+
#end
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Context management
|
2
|
+
#:include: ../shared/license.rdoc
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
#require 'ontomde-core/exceptions.rb'
|
6
|
+
|
7
|
+
#Internal use.
|
8
|
+
#
|
9
|
+
#Used for storing context.
|
10
|
+
class WarningHash < Hash
|
11
|
+
|
12
|
+
#Returns context value associated to key.
|
13
|
+
#Raises an error if key is not found.
|
14
|
+
# Returns default, when context is undefined for key, and a default value is provided.
|
15
|
+
def [](key,default=Object.class)
|
16
|
+
val=super(key)
|
17
|
+
return val unless val.nil?
|
18
|
+
#Note: Object.class is used as a magic number.
|
19
|
+
return default unless default==Object.class
|
20
|
+
raise Warning.new(), <<FINCODE
|
21
|
+
Evaluation interrompue:
|
22
|
+
La session ne contient pas la variable :#{key}.
|
23
|
+
L'exemple de code suivant permet de definir une variable de contexte:
|
24
|
+
|
25
|
+
votre code
|
26
|
+
mtk_context(:#{key}=>'valeur'){
|
27
|
+
votre code
|
28
|
+
puts context[:#{key}]
|
29
|
+
votre code
|
30
|
+
}
|
31
|
+
FINCODE
|
32
|
+
end
|
33
|
+
def get(key)
|
34
|
+
return self[key] if self.include?(key)
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Mrdf_Model
|
40
|
+
@@context=WarningHash.new()
|
41
|
+
|
42
|
+
def context
|
43
|
+
return @@context
|
44
|
+
end
|
45
|
+
|
46
|
+
# Similar to mtk_context but preserves already defined context.
|
47
|
+
# Used to provide a default context.
|
48
|
+
def mtk_default_context(*additional_context,&block)
|
49
|
+
filtered_context=Array.new
|
50
|
+
additional_context.each { |item| item.each { |k,v|
|
51
|
+
next if @@context.include?(k)
|
52
|
+
filtered_context << item
|
53
|
+
}}
|
54
|
+
mtk_context(*filtered_context,&block)
|
55
|
+
end
|
56
|
+
|
57
|
+
#Defines context variables for use in block passed as parameter.
|
58
|
+
#Existing context variable are redefined. (cf. mtk_default_context )
|
59
|
+
#When exiting block, previously defined context variables are restored.
|
60
|
+
#
|
61
|
+
#Example 1:
|
62
|
+
# mtk_context( :build => "build\", :option => true) {
|
63
|
+
# your-code
|
64
|
+
# puts context[:build]
|
65
|
+
# your-code
|
66
|
+
# puts context[:option]
|
67
|
+
# your-code
|
68
|
+
# }
|
69
|
+
#
|
70
|
+
#Example 2:
|
71
|
+
# mtk_context( :build => "BUILD_ONE\") {
|
72
|
+
# your-code
|
73
|
+
# puts context[:build] # BUILD_ONE
|
74
|
+
# mtk_context( :build => "NEW_DIR", :option => true) {
|
75
|
+
# your-code
|
76
|
+
# puts context[:build] # NEW_DIR\
|
77
|
+
# your-code
|
78
|
+
# puts context[:option]
|
79
|
+
# your-code
|
80
|
+
# }
|
81
|
+
# puts context[:build] # BUILD_ONE
|
82
|
+
# }
|
83
|
+
def mtk_context(*additional_context,&block)
|
84
|
+
context_save=@@context
|
85
|
+
@@context=context_save.clone
|
86
|
+
additional_context.each { |item| item.each { |k,v|
|
87
|
+
@@context[k]=v
|
88
|
+
}}
|
89
|
+
yield
|
90
|
+
@@context=context_save
|
91
|
+
return nil
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
module Mrdf_Resource
|
97
|
+
|
98
|
+
# returns current context
|
99
|
+
def context
|
100
|
+
return @rdf_model.context
|
101
|
+
end
|
102
|
+
|
103
|
+
# cf: Mrdf_Model::mtk_context
|
104
|
+
def mtk_context(*args,&block)
|
105
|
+
return @rdf_model.mtk_context(*args,&block)
|
106
|
+
end
|
107
|
+
#
|
108
|
+
# cf: Mrdf_Model::mtk_default_context
|
109
|
+
def mtk_default_context(*args,&block)
|
110
|
+
return @rdf_model.mtk_default_context(*args,&block)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
|
@@ -0,0 +1,842 @@
|
|
1
|
+
|
2
|
+
class Crdf_Ressource
|
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
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
# = CustomERB -- Ruby Templating
|
17
|
+
#
|
18
|
+
# Author:: Masatoshi SEKI
|
19
|
+
# Documentation:: James Edward Gray II and Gavin Sinclair
|
20
|
+
#
|
21
|
+
# See CustomERB for primary documentation and CustomERB::Util for a couple of utility
|
22
|
+
# routines.
|
23
|
+
#
|
24
|
+
# Copyright (c) 1999-2000,2002,2003 Masatoshi SEKI
|
25
|
+
#
|
26
|
+
# You can redistribute it and/or modify it under the same terms as Ruby.
|
27
|
+
|
28
|
+
#
|
29
|
+
# = CustomERB -- Ruby Templating
|
30
|
+
#
|
31
|
+
# == Introduction
|
32
|
+
#
|
33
|
+
# CustomERB provides an easy to use but powerful templating system for Ruby. Using
|
34
|
+
# CustomERB, actual Ruby code can be added to any plain text document for the
|
35
|
+
# purposes of generating document information details and/or flow control.
|
36
|
+
#
|
37
|
+
# A very simple example is this:
|
38
|
+
#
|
39
|
+
# require 'erb'
|
40
|
+
#
|
41
|
+
# x = 42
|
42
|
+
# template = CustomERB.new <<-EOF
|
43
|
+
# The value of x is: <@= x @>
|
44
|
+
# EOF
|
45
|
+
# puts template.result(binding)
|
46
|
+
#
|
47
|
+
# <em>Prints:</em> The value of x is: 42
|
48
|
+
#
|
49
|
+
# More complex examples are given below.
|
50
|
+
#
|
51
|
+
#
|
52
|
+
# == Recognized Tags
|
53
|
+
#
|
54
|
+
# CustomERB recognizes certain tags in the provided template and converts them based
|
55
|
+
# on the rules below:
|
56
|
+
#
|
57
|
+
# <@ Ruby code -- inline with output @>
|
58
|
+
# <@= Ruby expression -- replace with result @>
|
59
|
+
# <@# comment -- ignored -- useful in testing @>
|
60
|
+
# @ a line of Ruby code -- treated as <@ line @> (optional -- see CustomERB.new)
|
61
|
+
# @@ replaced with @ if first thing on a line and @ processing is used
|
62
|
+
# <@@ or @@> -- replace with <@ or @> respectively
|
63
|
+
#
|
64
|
+
# All other text is passed through CustomERB filtering unchanged.
|
65
|
+
#
|
66
|
+
#
|
67
|
+
# == Options
|
68
|
+
#
|
69
|
+
# There are several settings you can change when you use CustomERB:
|
70
|
+
# * the nature of the tags that are recognized;
|
71
|
+
# * the value of <tt>$SAFE</tt> under which the template is run;
|
72
|
+
# * the binding used to resolve local variables in the template.
|
73
|
+
#
|
74
|
+
# See the CustomERB.new and CustomERB#result methods for more detail.
|
75
|
+
#
|
76
|
+
#
|
77
|
+
# == Examples
|
78
|
+
#
|
79
|
+
# === Plain Text
|
80
|
+
#
|
81
|
+
# CustomERB is useful for any generic templating situation. Note that in this example, we use the
|
82
|
+
# convenient "@ at start of line" tag, and we quote the template literally with
|
83
|
+
# <tt>@q{...}</tt> to avoid trouble with the backslash.
|
84
|
+
#
|
85
|
+
# require "erb"
|
86
|
+
#
|
87
|
+
# # Create template.
|
88
|
+
# template = @q{
|
89
|
+
# From: James Edward Gray II <james@grayproductions.net>
|
90
|
+
# To: <@= to @>
|
91
|
+
# Subject: Addressing Needs
|
92
|
+
#
|
93
|
+
# <@= to[/\w+/] @>:
|
94
|
+
#
|
95
|
+
# Just wanted to send a quick note assuring that your needs are being
|
96
|
+
# addressed.
|
97
|
+
#
|
98
|
+
# I want you to know that my team will keep working on the issues,
|
99
|
+
# especially:
|
100
|
+
#
|
101
|
+
# <@# ignore numerous minor requests -- focus on priorities @>
|
102
|
+
# @ priorities.each do |priority|
|
103
|
+
# * <@= priority @>
|
104
|
+
# @ end
|
105
|
+
#
|
106
|
+
# Thanks for your patience.
|
107
|
+
#
|
108
|
+
# James Edward Gray II
|
109
|
+
# }.gsub(/^ /, '')
|
110
|
+
#
|
111
|
+
# message = CustomERB.new(template, 0, "@<>")
|
112
|
+
#
|
113
|
+
# # Set up template data.
|
114
|
+
# to = "Community Spokesman <spokesman@ruby_community.org>"
|
115
|
+
# priorities = [ "Run Ruby Quiz",
|
116
|
+
# "Document Modules",
|
117
|
+
# "Answer Questions on Ruby Talk" ]
|
118
|
+
#
|
119
|
+
# # Produce result.
|
120
|
+
# email = message.result
|
121
|
+
# puts email
|
122
|
+
#
|
123
|
+
# <i>Generates:</i>
|
124
|
+
#
|
125
|
+
# From: James Edward Gray II <james@grayproductions.net>
|
126
|
+
# To: Community Spokesman <spokesman@ruby_community.org>
|
127
|
+
# Subject: Addressing Needs
|
128
|
+
#
|
129
|
+
# Community:
|
130
|
+
#
|
131
|
+
# Just wanted to send a quick note assuring that your needs are being addressed.
|
132
|
+
#
|
133
|
+
# I want you to know that my team will keep working on the issues, especially:
|
134
|
+
#
|
135
|
+
# * Run Ruby Quiz
|
136
|
+
# * Document Modules
|
137
|
+
# * Answer Questions on Ruby Talk
|
138
|
+
#
|
139
|
+
# Thanks for your patience.
|
140
|
+
#
|
141
|
+
# James Edward Gray II
|
142
|
+
#
|
143
|
+
# === Ruby in HTML
|
144
|
+
#
|
145
|
+
# CustomERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
|
146
|
+
# this example to provide a special binding when the template is run, so that the instance
|
147
|
+
# variables in the Product object can be resolved.
|
148
|
+
#
|
149
|
+
# require "erb"
|
150
|
+
#
|
151
|
+
# # Build template data class.
|
152
|
+
# class Product
|
153
|
+
# def initialize( code, name, desc, cost )
|
154
|
+
# @code = code
|
155
|
+
# @name = name
|
156
|
+
# @desc = desc
|
157
|
+
# @cost = cost
|
158
|
+
#
|
159
|
+
# @features = [ ]
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
# def add_feature( feature )
|
163
|
+
# @features << feature
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# # Support templating of member data.
|
167
|
+
# def get_binding
|
168
|
+
# binding
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
# # ...
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
# # Create template.
|
175
|
+
# template = @{
|
176
|
+
# <html>
|
177
|
+
# <head><title>Ruby Toys -- <@= @name @></title></head>
|
178
|
+
# <body>
|
179
|
+
#
|
180
|
+
# <h1><@= @name @> (<@= @code @>)</h1>
|
181
|
+
# <p><@= @desc @></p>
|
182
|
+
#
|
183
|
+
# <ul>
|
184
|
+
# <@ @features.each do |f| @>
|
185
|
+
# <li><b><@= f @></b></li>
|
186
|
+
# <@ end @>
|
187
|
+
# </ul>
|
188
|
+
#
|
189
|
+
# <p>
|
190
|
+
# <@ if @cost < 10 @>
|
191
|
+
# <b>Only <@= @cost @>!!!</b>
|
192
|
+
# <@ else @>
|
193
|
+
# Call for a price, today!
|
194
|
+
# <@ end @>
|
195
|
+
# </p>
|
196
|
+
#
|
197
|
+
# </body>
|
198
|
+
# </html>
|
199
|
+
# }.gsub(/^ /, '')
|
200
|
+
#
|
201
|
+
# rhtml = CustomERB.new(template)
|
202
|
+
#
|
203
|
+
# # Set up template data.
|
204
|
+
# toy = Product.new( "TZ-1002",
|
205
|
+
# "Rubysapien",
|
206
|
+
# "Geek's Best Friend! Responds to Ruby commands...",
|
207
|
+
# 999.95 )
|
208
|
+
# toy.add_feature("Listens for verbal commands in the Ruby language!")
|
209
|
+
# toy.add_feature("Ignores Perl, Java, and all C variants.")
|
210
|
+
# toy.add_feature("Karate-Chop Action!!!")
|
211
|
+
# toy.add_feature("Matz signature on left leg.")
|
212
|
+
# toy.add_feature("Gem studded eyes... Rubies, of course!")
|
213
|
+
#
|
214
|
+
# # Produce result.
|
215
|
+
# rhtml.run(toy.get_binding)
|
216
|
+
#
|
217
|
+
# <i>Generates (some blank lines removed):</i>
|
218
|
+
#
|
219
|
+
# <html>
|
220
|
+
# <head><title>Ruby Toys -- Rubysapien</title></head>
|
221
|
+
# <body>
|
222
|
+
#
|
223
|
+
# <h1>Rubysapien (TZ-1002)</h1>
|
224
|
+
# <p>Geek's Best Friend! Responds to Ruby commands...</p>
|
225
|
+
#
|
226
|
+
# <ul>
|
227
|
+
# <li><b>Listens for verbal commands in the Ruby language!</b></li>
|
228
|
+
# <li><b>Ignores Perl, Java, and all C variants.</b></li>
|
229
|
+
# <li><b>Karate-Chop Action!!!</b></li>
|
230
|
+
# <li><b>Matz signature on left leg.</b></li>
|
231
|
+
# <li><b>Gem studded eyes... Rubies, of course!</b></li>
|
232
|
+
# </ul>
|
233
|
+
#
|
234
|
+
# <p>
|
235
|
+
# Call for a price, today!
|
236
|
+
# </p>
|
237
|
+
#
|
238
|
+
# </body>
|
239
|
+
# </html>
|
240
|
+
#
|
241
|
+
#
|
242
|
+
# == Notes
|
243
|
+
#
|
244
|
+
# There are a variety of templating solutions available in various Ruby projects:
|
245
|
+
# * CustomERB's big brother, eRuby, works the same but is written in C for speed;
|
246
|
+
# * Amrita (smart at producing HTML/XML);
|
247
|
+
# * cs/Template (written in C for speed);
|
248
|
+
# * RDoc, distributed with Ruby, uses its own template engine, which can be reused elsewhere;
|
249
|
+
# * and others; search the RAA.
|
250
|
+
#
|
251
|
+
# Rails, the web application framework, uses CustomERB to create views.
|
252
|
+
#
|
253
|
+
class CustomERB
|
254
|
+
Revision = '$Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $' #'
|
255
|
+
|
256
|
+
# Returns revision information for the erb.rb module.
|
257
|
+
def self.version
|
258
|
+
"erb.rb [2.0.4 #{CustomERB::Revision.split[1]}]"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
#--
|
263
|
+
# CustomERB::Compiler
|
264
|
+
class CustomERB
|
265
|
+
class Compiler # :nodoc:
|
266
|
+
class PercentLine # :nodoc:
|
267
|
+
def initialize(str)
|
268
|
+
@value = str
|
269
|
+
end
|
270
|
+
attr_reader :value
|
271
|
+
alias :to_s :value
|
272
|
+
end
|
273
|
+
|
274
|
+
class Scanner # :nodoc:
|
275
|
+
SplitRegexp = /(<@@)|(@@>)|(<@=)|(<@#)|(<@)|(@>)|(\n)/
|
276
|
+
|
277
|
+
@scanner_map = {}
|
278
|
+
def self.regist_scanner(klass, trim_mode, percent)
|
279
|
+
@scanner_map[[trim_mode, percent]] = klass
|
280
|
+
end
|
281
|
+
|
282
|
+
def self.default_scanner=(klass)
|
283
|
+
@default_scanner = klass
|
284
|
+
end
|
285
|
+
|
286
|
+
def self.make_scanner(src, trim_mode, percent)
|
287
|
+
klass = @scanner_map.fetch([trim_mode, percent], @default_scanner)
|
288
|
+
klass.new(src, trim_mode, percent)
|
289
|
+
end
|
290
|
+
|
291
|
+
def initialize(src, trim_mode, percent)
|
292
|
+
@src = src
|
293
|
+
@stag = nil
|
294
|
+
end
|
295
|
+
attr_accessor :stag
|
296
|
+
|
297
|
+
def scan; end
|
298
|
+
end
|
299
|
+
|
300
|
+
class TrimScanner < Scanner # :nodoc:
|
301
|
+
TrimSplitRegexp = /(<@@)|(@@>)|(<@=)|(<@#)|(<@)|(@>\n)|(@>)|(\n)/
|
302
|
+
|
303
|
+
def initialize(src, trim_mode, percent)
|
304
|
+
super
|
305
|
+
@trim_mode = trim_mode
|
306
|
+
@percent = percent
|
307
|
+
if @trim_mode == '>'
|
308
|
+
@scan_line = self.method(:trim_line1)
|
309
|
+
elsif @trim_mode == '<>'
|
310
|
+
@scan_line = self.method(:trim_line2)
|
311
|
+
elsif @trim_mode == '-'
|
312
|
+
@scan_line = self.method(:explicit_trim_line)
|
313
|
+
else
|
314
|
+
@scan_line = self.method(:scan_line)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
attr_accessor :stag
|
318
|
+
|
319
|
+
def scan(&block)
|
320
|
+
@stag = nil
|
321
|
+
if @percent
|
322
|
+
@src.each do |line|
|
323
|
+
percent_line(line, &block)
|
324
|
+
end
|
325
|
+
else
|
326
|
+
@src.each do |line|
|
327
|
+
@scan_line.call(line, &block)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
nil
|
331
|
+
end
|
332
|
+
|
333
|
+
def percent_line(line, &block)
|
334
|
+
if @stag || line[0] != ?@
|
335
|
+
return @scan_line.call(line, &block)
|
336
|
+
end
|
337
|
+
|
338
|
+
line[0] = ''
|
339
|
+
if line[0] == ?@
|
340
|
+
@scan_line.call(line, &block)
|
341
|
+
else
|
342
|
+
yield(PercentLine.new(line.chomp))
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def scan_line(line)
|
347
|
+
line.split(SplitRegexp).each do |token|
|
348
|
+
next if token.empty?
|
349
|
+
yield(token)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def trim_line1(line)
|
354
|
+
line.split(TrimSplitRegexp).each do |token|
|
355
|
+
next if token.empty?
|
356
|
+
if token == "@>\n"
|
357
|
+
yield('@>')
|
358
|
+
yield(:cr)
|
359
|
+
break
|
360
|
+
end
|
361
|
+
yield(token)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def trim_line2(line)
|
366
|
+
head = nil
|
367
|
+
line.split(TrimSplitRegexp).each do |token|
|
368
|
+
next if token.empty?
|
369
|
+
head = token unless head
|
370
|
+
if token == "@>\n"
|
371
|
+
yield('@>')
|
372
|
+
if is_erb_stag?(head)
|
373
|
+
yield(:cr)
|
374
|
+
else
|
375
|
+
yield("\n")
|
376
|
+
end
|
377
|
+
break
|
378
|
+
end
|
379
|
+
yield(token)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
ExplicitTrimRegexp = /(^[ \t]*<@-)|(-@>\n?\z)|(<@-)|(-@>)|(<@@)|(@@>)|(<@=)|(<@#)|(<@)|(@>)|(\n)/
|
384
|
+
def explicit_trim_line(line)
|
385
|
+
line.split(ExplicitTrimRegexp).each do |token|
|
386
|
+
next if token.empty?
|
387
|
+
if @stag.nil? && /[ \t]*<@-/ =~ token
|
388
|
+
yield('<@')
|
389
|
+
elsif @stag && /-@>\n/ =~ token
|
390
|
+
yield('@>')
|
391
|
+
yield(:cr)
|
392
|
+
elsif @stag && token == '-@>'
|
393
|
+
yield('@>')
|
394
|
+
else
|
395
|
+
yield(token)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
CustomERB_STAG = %w(<@= <@# <@)
|
401
|
+
def is_erb_stag?(s)
|
402
|
+
CustomERB_STAG.member?(s)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
Scanner.default_scanner = TrimScanner
|
407
|
+
|
408
|
+
class SimpleScanner < Scanner # :nodoc:
|
409
|
+
def scan
|
410
|
+
@src.each do |line|
|
411
|
+
line.split(SplitRegexp).each do |token|
|
412
|
+
next if token.empty?
|
413
|
+
yield(token)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
Scanner.regist_scanner(SimpleScanner, nil, false)
|
420
|
+
|
421
|
+
begin
|
422
|
+
require 'strscan'
|
423
|
+
class SimpleScanner2 < Scanner # :nodoc:
|
424
|
+
def scan
|
425
|
+
stag_reg = /(.*?)(<@@|<@=|<@#|<@|\n|\z)/
|
426
|
+
etag_reg = /(.*?)(@@>|@>|\n|\z)/
|
427
|
+
scanner = StringScanner.new(@src)
|
428
|
+
while ! scanner.eos?
|
429
|
+
scanner.scan(@stag ? etag_reg : stag_reg)
|
430
|
+
text = scanner[1]
|
431
|
+
elem = scanner[2]
|
432
|
+
yield(text) unless text.empty?
|
433
|
+
yield(elem) unless elem.empty?
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
Scanner.regist_scanner(SimpleScanner2, nil, false)
|
438
|
+
|
439
|
+
class PercentScanner < Scanner # :nodoc:
|
440
|
+
def scan
|
441
|
+
new_line = true
|
442
|
+
stag_reg = /(.*?)(<@@|<@=|<@#|<@|\n|\z)/
|
443
|
+
etag_reg = /(.*?)(@@>|@>|\n|\z)/
|
444
|
+
scanner = StringScanner.new(@src)
|
445
|
+
while ! scanner.eos?
|
446
|
+
if new_line && @stag.nil?
|
447
|
+
if scanner.scan(/@@/)
|
448
|
+
yield('@')
|
449
|
+
new_line = false
|
450
|
+
next
|
451
|
+
elsif scanner.scan(/@/)
|
452
|
+
yield(PercentLine.new(scanner.scan(/.*?(\n|\z)/).chomp))
|
453
|
+
next
|
454
|
+
end
|
455
|
+
end
|
456
|
+
scanner.scan(@stag ? etag_reg : stag_reg)
|
457
|
+
text = scanner[1]
|
458
|
+
elem = scanner[2]
|
459
|
+
yield(text) unless text.empty?
|
460
|
+
yield(elem) unless elem.empty?
|
461
|
+
new_line = (elem == "\n")
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|
465
|
+
Scanner.regist_scanner(PercentScanner, nil, true)
|
466
|
+
|
467
|
+
class ExplicitScanner < Scanner # :nodoc:
|
468
|
+
def scan
|
469
|
+
new_line = true
|
470
|
+
stag_reg = /(.*?)(<@@|<@=|<@#|<@-|<@|\n|\z)/
|
471
|
+
etag_reg = /(.*?)(@@>|-@>|@>|\n|\z)/
|
472
|
+
scanner = StringScanner.new(@src)
|
473
|
+
while ! scanner.eos?
|
474
|
+
if new_line && @stag.nil? && scanner.scan(/[ \t]*<@-/)
|
475
|
+
yield('<@')
|
476
|
+
new_line = false
|
477
|
+
next
|
478
|
+
end
|
479
|
+
scanner.scan(@stag ? etag_reg : stag_reg)
|
480
|
+
text = scanner[1]
|
481
|
+
elem = scanner[2]
|
482
|
+
new_line = (elem == "\n")
|
483
|
+
yield(text) unless text.empty?
|
484
|
+
if elem == '-@>'
|
485
|
+
yield('@>')
|
486
|
+
if scanner.scan(/(\n|\z)/)
|
487
|
+
yield(:cr)
|
488
|
+
new_line = true
|
489
|
+
end
|
490
|
+
elsif elem == '<@-'
|
491
|
+
yield('<@')
|
492
|
+
else
|
493
|
+
yield(elem) unless elem.empty?
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
Scanner.regist_scanner(ExplicitScanner, '-', false)
|
499
|
+
|
500
|
+
rescue LoadError
|
501
|
+
end
|
502
|
+
|
503
|
+
class Buffer # :nodoc:
|
504
|
+
def initialize(compiler)
|
505
|
+
@compiler = compiler
|
506
|
+
@line = []
|
507
|
+
@script = ""
|
508
|
+
@compiler.pre_cmd.each do |x|
|
509
|
+
push(x)
|
510
|
+
end
|
511
|
+
end
|
512
|
+
attr_reader :script
|
513
|
+
|
514
|
+
def push(cmd)
|
515
|
+
@line << cmd
|
516
|
+
end
|
517
|
+
|
518
|
+
def cr
|
519
|
+
@script << (@line.join('; '))
|
520
|
+
@line = []
|
521
|
+
@script << "\n"
|
522
|
+
end
|
523
|
+
|
524
|
+
def close
|
525
|
+
return unless @line
|
526
|
+
@compiler.post_cmd.each do |x|
|
527
|
+
push(x)
|
528
|
+
end
|
529
|
+
@script << (@line.join('; '))
|
530
|
+
@line = nil
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
def compile(s)
|
535
|
+
out = Buffer.new(self)
|
536
|
+
|
537
|
+
content = ''
|
538
|
+
scanner = make_scanner(s)
|
539
|
+
scanner.scan do |token|
|
540
|
+
if scanner.stag.nil?
|
541
|
+
case token
|
542
|
+
when PercentLine
|
543
|
+
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
544
|
+
content = ''
|
545
|
+
out.push(token.to_s)
|
546
|
+
out.cr
|
547
|
+
when :cr
|
548
|
+
out.cr
|
549
|
+
when '<@', '<@=', '<@#'
|
550
|
+
scanner.stag = token
|
551
|
+
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
552
|
+
content = ''
|
553
|
+
when "\n"
|
554
|
+
content << "\n"
|
555
|
+
out.push("#{@put_cmd} #{content.dump}")
|
556
|
+
out.cr
|
557
|
+
content = ''
|
558
|
+
when '<@@'
|
559
|
+
content << '<@'
|
560
|
+
else
|
561
|
+
content << token
|
562
|
+
end
|
563
|
+
else
|
564
|
+
case token
|
565
|
+
when '@>'
|
566
|
+
case scanner.stag
|
567
|
+
when '<@'
|
568
|
+
if content[-1] == ?\n
|
569
|
+
content.chop!
|
570
|
+
out.push(content)
|
571
|
+
out.cr
|
572
|
+
else
|
573
|
+
out.push(content)
|
574
|
+
end
|
575
|
+
when '<@='
|
576
|
+
out.push("#{@insert_cmd}((#{content}).to_s)")
|
577
|
+
when '<@#'
|
578
|
+
# out.push("# #{content.dump}")
|
579
|
+
end
|
580
|
+
scanner.stag = nil
|
581
|
+
content = ''
|
582
|
+
when '@@>'
|
583
|
+
content << '@>'
|
584
|
+
else
|
585
|
+
content << token
|
586
|
+
end
|
587
|
+
end
|
588
|
+
end
|
589
|
+
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
590
|
+
out.close
|
591
|
+
out.script
|
592
|
+
end
|
593
|
+
|
594
|
+
def prepare_trim_mode(mode)
|
595
|
+
case mode
|
596
|
+
when 1
|
597
|
+
return [false, '>']
|
598
|
+
when 2
|
599
|
+
return [false, '<>']
|
600
|
+
when 0
|
601
|
+
return [false, nil]
|
602
|
+
when String
|
603
|
+
perc = mode.include?('@')
|
604
|
+
if mode.include?('-')
|
605
|
+
return [perc, '-']
|
606
|
+
elsif mode.include?('<>')
|
607
|
+
return [perc, '<>']
|
608
|
+
elsif mode.include?('>')
|
609
|
+
return [perc, '>']
|
610
|
+
else
|
611
|
+
[perc, nil]
|
612
|
+
end
|
613
|
+
else
|
614
|
+
return [false, nil]
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
def make_scanner(src)
|
619
|
+
Scanner.make_scanner(src, @trim_mode, @percent)
|
620
|
+
end
|
621
|
+
|
622
|
+
def initialize(trim_mode)
|
623
|
+
@percent, @trim_mode = prepare_trim_mode(trim_mode)
|
624
|
+
@put_cmd = 'print'
|
625
|
+
@insert_cmd = @put_cmd
|
626
|
+
@pre_cmd = []
|
627
|
+
@post_cmd = []
|
628
|
+
end
|
629
|
+
attr_reader :percent, :trim_mode
|
630
|
+
attr_accessor :put_cmd, :insert_cmd, :pre_cmd, :post_cmd
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
#--
|
635
|
+
# CustomERB
|
636
|
+
class CustomERB
|
637
|
+
#
|
638
|
+
# Constructs a new CustomERB object with the template specified in _str_.
|
639
|
+
#
|
640
|
+
# An CustomERB object works by building a chunk of Ruby code that will output
|
641
|
+
# the completed template when run. If _safe_level_ is set to a non-nil value,
|
642
|
+
# CustomERB code will be run in a separate thread with <b>$SAFE</b> set to the
|
643
|
+
# provided level.
|
644
|
+
#
|
645
|
+
# If _trim_mode_ is passed a String containing one or more of the following
|
646
|
+
# modifiers, CustomERB will adjust its code generation as listed:
|
647
|
+
#
|
648
|
+
# @ enables Ruby code processing for lines beginning with @
|
649
|
+
# <> omit newline for lines starting with <@ and ending in @>
|
650
|
+
# > omit newline for lines ending in @>
|
651
|
+
#
|
652
|
+
# _eoutvar_ can be used to set the name of the variable CustomERB will build up
|
653
|
+
# its output in. This is useful when you need to run multiple CustomERB
|
654
|
+
# templates through the same binding and/or when you want to control where
|
655
|
+
# output ends up. Pass the name of the variable to be used inside a String.
|
656
|
+
#
|
657
|
+
# === Example
|
658
|
+
#
|
659
|
+
# require "erb"
|
660
|
+
#
|
661
|
+
# # build data class
|
662
|
+
# class Listings
|
663
|
+
# PRODUCT = { :name => "Chicken Fried Steak",
|
664
|
+
# :desc => "A well messages pattie, breaded and fried.",
|
665
|
+
# :cost => 9.95 }
|
666
|
+
#
|
667
|
+
# attr_reader :product, :price
|
668
|
+
#
|
669
|
+
# def initialize( product = "", price = "" )
|
670
|
+
# @product = product
|
671
|
+
# @price = price
|
672
|
+
# end
|
673
|
+
#
|
674
|
+
# def build
|
675
|
+
# b = binding
|
676
|
+
# # create and run templates, filling member data variebles
|
677
|
+
# CustomERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), 0, "", "@product").result b
|
678
|
+
# <@= PRODUCT[:name] @>
|
679
|
+
# <@= PRODUCT[:desc] @>
|
680
|
+
# END_PRODUCT
|
681
|
+
# CustomERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), 0, "", "@price").result b
|
682
|
+
# <@= PRODUCT[:name] @> -- <@= PRODUCT[:cost] @>
|
683
|
+
# <@= PRODUCT[:desc] @>
|
684
|
+
# END_PRICE
|
685
|
+
# end
|
686
|
+
# end
|
687
|
+
#
|
688
|
+
# # setup template data
|
689
|
+
# listings = Listings.new
|
690
|
+
# listings.build
|
691
|
+
#
|
692
|
+
# puts listings.product + "\n" + listings.price
|
693
|
+
#
|
694
|
+
# _Generates_
|
695
|
+
#
|
696
|
+
# Chicken Fried Steak
|
697
|
+
# A well messages pattie, breaded and fried.
|
698
|
+
#
|
699
|
+
# Chicken Fried Steak -- 9.95
|
700
|
+
# A well messages pattie, breaded and fried.
|
701
|
+
#
|
702
|
+
def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
|
703
|
+
@safe_level = safe_level
|
704
|
+
compiler = CustomERB::Compiler.new(trim_mode)
|
705
|
+
set_eoutvar(compiler, eoutvar)
|
706
|
+
@src = compiler.compile(str)
|
707
|
+
@filename = nil
|
708
|
+
end
|
709
|
+
|
710
|
+
# The Ruby code generated by CustomERB
|
711
|
+
attr_reader :src
|
712
|
+
|
713
|
+
# The optional _filename_ argument passed to Kernel#eval when the CustomERB code
|
714
|
+
# is run
|
715
|
+
attr_accessor :filename
|
716
|
+
|
717
|
+
#
|
718
|
+
# Can be used to set _eoutvar_ as described in CustomERB#new. It's probably easier
|
719
|
+
# to just use the constructor though, since calling this method requires the
|
720
|
+
# setup of an CustomERB _compiler_ object.
|
721
|
+
#
|
722
|
+
def set_eoutvar(compiler, eoutvar = '_erbout')
|
723
|
+
compiler.put_cmd = "#{eoutvar}.concat"
|
724
|
+
compiler.insert_cmd = "#{eoutvar}.concat"
|
725
|
+
|
726
|
+
cmd = []
|
727
|
+
cmd.push "#{eoutvar} = ''"
|
728
|
+
|
729
|
+
compiler.pre_cmd = cmd
|
730
|
+
|
731
|
+
cmd = []
|
732
|
+
cmd.push(eoutvar)
|
733
|
+
|
734
|
+
compiler.post_cmd = cmd
|
735
|
+
end
|
736
|
+
|
737
|
+
# Generate results and print them. (see CustomERB#result)
|
738
|
+
def run(b=TOPLEVEL_BINDING)
|
739
|
+
print self.result(b)
|
740
|
+
end
|
741
|
+
|
742
|
+
#
|
743
|
+
# Executes the generated CustomERB code to produce a completed template, returning
|
744
|
+
# the results of that code. (See CustomERB#new for details on how this process can
|
745
|
+
# be affected by _safe_level_.)
|
746
|
+
#
|
747
|
+
# _b_ accepts a Binding or Proc object which is used to set the context of
|
748
|
+
# code evaluation.
|
749
|
+
#
|
750
|
+
def result(b=TOPLEVEL_BINDING)
|
751
|
+
if @safe_level
|
752
|
+
th = Thread.start {
|
753
|
+
$SAFE = @safe_level
|
754
|
+
eval(@src, b, (@filename || '(erb)'), 1)
|
755
|
+
}
|
756
|
+
return th.value
|
757
|
+
else
|
758
|
+
return eval(@src, b, (@filename || '(erb)'), 1)
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
def def_method(mod, methodname, fname='(CustomERB)') # :nodoc:
|
763
|
+
mod.module_eval("def #{methodname}\n" + self.src + "\nend\n", fname, 0)
|
764
|
+
end
|
765
|
+
|
766
|
+
def def_module(methodname='erb') # :nodoc:
|
767
|
+
mod = Module.new
|
768
|
+
def_method(mod, methodname)
|
769
|
+
mod
|
770
|
+
end
|
771
|
+
|
772
|
+
def def_class(superklass=Object, methodname='result') # :nodoc:
|
773
|
+
cls = Class.new(superklass)
|
774
|
+
def_method(cls, methodname)
|
775
|
+
cls
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
#--
|
780
|
+
# CustomERB::Util
|
781
|
+
class CustomERB
|
782
|
+
# A utility module for conversion routines, often handy in HTML generation.
|
783
|
+
module Util
|
784
|
+
public
|
785
|
+
#
|
786
|
+
# A utility method for escaping HTML tag characters in _s_.
|
787
|
+
#
|
788
|
+
# require "erb"
|
789
|
+
# include CustomERB::Util
|
790
|
+
#
|
791
|
+
# puts html_escape("is a > 0 & a < 10?")
|
792
|
+
#
|
793
|
+
# _Generates_
|
794
|
+
#
|
795
|
+
# is a > 0 & a < 10?
|
796
|
+
#
|
797
|
+
def html_escape(s)
|
798
|
+
s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<")
|
799
|
+
end
|
800
|
+
alias h html_escape
|
801
|
+
module_function :h
|
802
|
+
module_function :html_escape
|
803
|
+
|
804
|
+
#
|
805
|
+
# A utility method for encoding the String _s_ as a URL.
|
806
|
+
#
|
807
|
+
# require "erb"
|
808
|
+
# include CustomERB::Util
|
809
|
+
#
|
810
|
+
# puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
|
811
|
+
#
|
812
|
+
# _Generates_
|
813
|
+
#
|
814
|
+
# Programming@20Ruby@3A@20@20The@20Pragmatic@20Programmer@27s@20Guide
|
815
|
+
#
|
816
|
+
def url_encode(s)
|
817
|
+
s.to_s.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("@@@02X", $&.unpack("C")[0]) }
|
818
|
+
end
|
819
|
+
alias u url_encode
|
820
|
+
module_function :u
|
821
|
+
module_function :url_encode
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
#--
|
826
|
+
# CustomERB::DefMethod
|
827
|
+
class CustomERB
|
828
|
+
module DefMethod # :nodoc:
|
829
|
+
public
|
830
|
+
def def_erb_method(methodname, erb)
|
831
|
+
if erb.kind_of? String
|
832
|
+
fname = erb
|
833
|
+
File.open(fname) {|f| erb = CustomERB.new(f.read) }
|
834
|
+
erb.def_method(self, methodname, fname)
|
835
|
+
else
|
836
|
+
erb.def_method(self, methodname)
|
837
|
+
end
|
838
|
+
end
|
839
|
+
module_function :def_erb_method
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|