Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
02e88019
Commit
02e88019
authored
Jan 11, 2011
by
Rob Pike
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
template: allow accesses only to exported fields and methods
R=rsc, gri CC=golang-dev
https://golang.org/cl/3890042
parent
ac1c0945
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
125 additions
and
110 deletions
+125
-110
src/pkg/template/template.go
src/pkg/template/template.go
+14
-0
src/pkg/template/template_test.go
src/pkg/template/template_test.go
+111
-110
No files found.
src/pkg/template/template.go
View file @
02e88019
...
...
@@ -73,6 +73,8 @@ import (
"os"
"reflect"
"strings"
"unicode"
"utf8"
)
// Errors returned during parsing and execution. Users may extract the information and reformat
...
...
@@ -198,6 +200,12 @@ func (t *Template) parseError(err string, args ...interface{}) {
panic
(
&
Error
{
t
.
linenum
,
fmt
.
Sprintf
(
err
,
args
...
)})
}
// Is this an exported - upper case - name?
func
isExported
(
name
string
)
bool
{
rune
,
_
:=
utf8
.
DecodeRuneInString
(
name
)
return
unicode
.
IsUpper
(
rune
)
}
// -- Lexical analysis
// Is c a white space character?
...
...
@@ -596,6 +604,9 @@ func lookup(v reflect.Value, name string) reflect.Value {
m
:=
typ
.
Method
(
i
)
mtyp
:=
m
.
Type
if
m
.
Name
==
name
&&
mtyp
.
NumIn
()
==
1
&&
mtyp
.
NumOut
()
==
1
{
if
!
isExported
(
name
)
{
return
nil
}
return
v
.
Method
(
i
)
.
Call
(
nil
)[
0
]
}
}
...
...
@@ -606,6 +617,9 @@ func lookup(v reflect.Value, name string) reflect.Value {
case
*
reflect
.
InterfaceValue
:
v
=
av
.
Elem
()
case
*
reflect
.
StructValue
:
if
!
isExported
(
name
)
{
return
nil
}
return
av
.
FieldByName
(
name
)
case
*
reflect
.
MapValue
:
return
av
.
Elem
(
reflect
.
NewValue
(
name
))
...
...
src/pkg/template/template_test.go
View file @
02e88019
...
...
@@ -20,40 +20,40 @@ type Test struct {
}
type
T
struct
{
i
tem
string
v
alue
string
I
tem
string
V
alue
string
}
type
U
struct
{
m
p
map
[
string
]
int
M
p
map
[
string
]
int
}
type
S
struct
{
h
eader
string
i
nteger
int
r
aw
string
i
nnerT
T
i
nnerPointerT
*
T
d
ata
[]
T
p
data
[]
*
T
e
mpty
[]
*
T
e
mptystring
string
n
ull
[]
*
T
v
ec
*
vector
.
Vector
t
rue
bool
f
alse
bool
m
p
map
[
string
]
string
json
interface
{}
i
nnermap
U
s
tringmap
map
[
string
]
string
b
ytes
[]
byte
i
face
interface
{}
i
faceptr
interface
{}
H
eader
string
I
nteger
int
R
aw
string
I
nnerT
T
I
nnerPointerT
*
T
D
ata
[]
T
P
data
[]
*
T
E
mpty
[]
*
T
E
mptystring
string
N
ull
[]
*
T
V
ec
*
vector
.
Vector
T
rue
bool
F
alse
bool
M
p
map
[
string
]
string
JSON
interface
{}
I
nnermap
U
S
tringmap
map
[
string
]
string
B
ytes
[]
byte
I
face
interface
{}
I
faceptr
interface
{}
}
func
(
s
*
S
)
p
ointerMethod
()
string
{
return
"ptrmethod!"
}
func
(
s
*
S
)
P
ointerMethod
()
string
{
return
"ptrmethod!"
}
func
(
s
S
)
v
alueMethod
()
string
{
return
"valmethod!"
}
func
(
s
S
)
V
alueMethod
()
string
{
return
"valmethod!"
}
var
t1
=
T
{
"ItemNumber1"
,
"ValueNumber1"
}
var
t2
=
T
{
"ItemNumber2"
,
"ValueNumber2"
}
...
...
@@ -112,48 +112,48 @@ var tests = []*Test{
// Variables at top level
&
Test
{
in
:
"{
header}={i
nteger}
\n
"
,
in
:
"{
Header}={I
nteger}
\n
"
,
out
:
"Header=77
\n
"
,
},
// Method at top level
&
Test
{
in
:
"ptrmethod={
p
ointerMethod}
\n
"
,
in
:
"ptrmethod={
P
ointerMethod}
\n
"
,
out
:
"ptrmethod=ptrmethod!
\n
"
,
},
&
Test
{
in
:
"valmethod={
v
alueMethod}
\n
"
,
in
:
"valmethod={
V
alueMethod}
\n
"
,
out
:
"valmethod=valmethod!
\n
"
,
},
// Section
&
Test
{
in
:
"{.section
d
ata }
\n
"
+
in
:
"{.section
D
ata }
\n
"
+
"some text for the section
\n
"
+
"{.end}
\n
"
,
out
:
"some text for the section
\n
"
,
},
&
Test
{
in
:
"{.section
d
ata }
\n
"
+
"{
header}={i
nteger}
\n
"
+
in
:
"{.section
D
ata }
\n
"
+
"{
Header}={I
nteger}
\n
"
+
"{.end}
\n
"
,
out
:
"Header=77
\n
"
,
},
&
Test
{
in
:
"{.section
p
data }
\n
"
+
"{
header}={i
nteger}
\n
"
+
in
:
"{.section
P
data }
\n
"
+
"{
Header}={I
nteger}
\n
"
+
"{.end}
\n
"
,
out
:
"Header=77
\n
"
,
},
&
Test
{
in
:
"{.section
p
data }
\n
"
+
in
:
"{.section
P
data }
\n
"
+
"data present
\n
"
+
"{.or}
\n
"
+
"data not present
\n
"
+
...
...
@@ -162,7 +162,7 @@ var tests = []*Test{
out
:
"data present
\n
"
,
},
&
Test
{
in
:
"{.section
e
mpty }
\n
"
+
in
:
"{.section
E
mpty }
\n
"
+
"data present
\n
"
+
"{.or}
\n
"
+
"data not present
\n
"
+
...
...
@@ -171,7 +171,7 @@ var tests = []*Test{
out
:
"data not present
\n
"
,
},
&
Test
{
in
:
"{.section
n
ull }
\n
"
+
in
:
"{.section
N
ull }
\n
"
+
"data present
\n
"
+
"{.or}
\n
"
+
"data not present
\n
"
+
...
...
@@ -180,10 +180,10 @@ var tests = []*Test{
out
:
"data not present
\n
"
,
},
&
Test
{
in
:
"{.section
p
data }
\n
"
+
"{
header}={i
nteger}
\n
"
+
in
:
"{.section
P
data }
\n
"
+
"{
Header}={I
nteger}
\n
"
+
"{.section @ }
\n
"
+
"{
header}={i
nteger}
\n
"
+
"{
Header}={I
nteger}
\n
"
+
"{.end}
\n
"
+
"{.end}
\n
"
,
...
...
@@ -192,22 +192,23 @@ var tests = []*Test{
},
&
Test
{
in
:
"{.section
data}{.end} {h
eader}
\n
"
,
in
:
"{.section
Data}{.end} {H
eader}
\n
"
,
out
:
" Header
\n
"
,
},
&
Test
{
in
:
"{.section
i
nteger}{@}{.end}"
,
in
:
"{.section
I
nteger}{@}{.end}"
,
out
:
"77"
,
},
// Repeated
&
Test
{
in
:
"{.section
p
data }
\n
"
+
in
:
"{.section
P
data }
\n
"
+
"{.repeated section @ }
\n
"
+
"{
item}={v
alue}
\n
"
+
"{
Item}={V
alue}
\n
"
+
"{.end}
\n
"
+
"{.end}
\n
"
,
...
...
@@ -215,9 +216,9 @@ var tests = []*Test{
"ItemNumber2=ValueNumber2
\n
"
,
},
&
Test
{
in
:
"{.section
p
data }
\n
"
+
in
:
"{.section
P
data }
\n
"
+
"{.repeated section @ }
\n
"
+
"{
item}={v
alue}
\n
"
+
"{
Item}={V
alue}
\n
"
+
"{.or}
\n
"
+
"this should not appear
\n
"
+
"{.end}
\n
"
+
...
...
@@ -228,8 +229,8 @@ var tests = []*Test{
},
&
Test
{
in
:
"{.section @ }
\n
"
+
"{.repeated section
e
mpty }
\n
"
+
"{
item}={v
alue}
\n
"
+
"{.repeated section
E
mpty }
\n
"
+
"{
Item}={V
alue}
\n
"
+
"{.or}
\n
"
+
"this should appear: empty field
\n
"
+
"{.end}
\n
"
+
...
...
@@ -238,8 +239,8 @@ var tests = []*Test{
out
:
"this should appear: empty field
\n
"
,
},
&
Test
{
in
:
"{.repeated section
p
data }
\n
"
+
"{
i
tem}
\n
"
+
in
:
"{.repeated section
P
data }
\n
"
+
"{
I
tem}
\n
"
+
"{.alternates with}
\n
"
+
"is
\n
over
\n
multiple
\n
lines
\n
"
+
"{.end}
\n
"
,
...
...
@@ -249,8 +250,8 @@ var tests = []*Test{
"ItemNumber2
\n
"
,
},
&
Test
{
in
:
"{.repeated section
p
data }
\n
"
+
"{
i
tem}
\n
"
+
in
:
"{.repeated section
P
data }
\n
"
+
"{
I
tem}
\n
"
+
"{.alternates with}
\n
"
+
"is
\n
over
\n
multiple
\n
lines
\n
"
+
" {.end}
\n
"
,
...
...
@@ -260,9 +261,9 @@ var tests = []*Test{
"ItemNumber2
\n
"
,
},
&
Test
{
in
:
"{.section
p
data }
\n
"
+
in
:
"{.section
P
data }
\n
"
+
"{.repeated section @ }
\n
"
+
"{
item}={v
alue}
\n
"
+
"{
Item}={V
alue}
\n
"
+
"{.alternates with}DIVIDER
\n
"
+
"{.or}
\n
"
+
"this should not appear
\n
"
+
...
...
@@ -274,7 +275,7 @@ var tests = []*Test{
"ItemNumber2=ValueNumber2
\n
"
,
},
&
Test
{
in
:
"{.repeated section
v
ec }
\n
"
+
in
:
"{.repeated section
V
ec }
\n
"
+
"{@}
\n
"
+
"{.end}
\n
"
,
...
...
@@ -283,28 +284,28 @@ var tests = []*Test{
},
// Same but with a space before {.end}: was a bug.
&
Test
{
in
:
"{.repeated section
v
ec }
\n
"
+
in
:
"{.repeated section
V
ec }
\n
"
+
"{@} {.end}
\n
"
,
out
:
"elt1 elt2
\n
"
,
},
&
Test
{
in
:
"{.repeated section
i
nteger}{.end}"
,
in
:
"{.repeated section
I
nteger}{.end}"
,
err
:
"line 1: .repeated: cannot repeat
i
nteger (type int)"
,
err
:
"line 1: .repeated: cannot repeat
I
nteger (type int)"
,
},
// Nested names
&
Test
{
in
:
"{.section @ }
\n
"
+
"{
innerT.item}={innerT.v
alue}
\n
"
+
"{
InnerT.Item}={InnerT.V
alue}
\n
"
+
"{.end}"
,
out
:
"ItemNumber1=ValueNumber1
\n
"
,
},
&
Test
{
in
:
"{.section @ }
\n
"
+
"{
innerT.item}={.section innerT}{.section v
alue}{@}{.end}{.end}
\n
"
+
"{
InnerT.Item}={.section InnerT}{.section V
alue}{@}{.end}{.end}
\n
"
+
"{.end}"
,
out
:
"ItemNumber1=ValueNumber1
\n
"
,
...
...
@@ -313,9 +314,9 @@ var tests = []*Test{
// Formatters
&
Test
{
in
:
"{.section
p
data }
\n
"
+
"{
header|uppercase}={i
nteger|+1}
\n
"
+
"{
header|html}={i
nteger|str}
\n
"
+
in
:
"{.section
P
data }
\n
"
+
"{
Header|uppercase}={I
nteger|+1}
\n
"
+
"{
Header|html}={I
nteger|str}
\n
"
+
"{.end}
\n
"
,
out
:
"HEADER=78
\n
"
+
...
...
@@ -323,10 +324,10 @@ var tests = []*Test{
},
&
Test
{
in
:
"{.section
p
data }
\n
"
+
"{
header|uppercase}={integer h
eader|multiword}
\n
"
+
"{
header|html}={header i
nteger|multiword}
\n
"
+
"{
header|html}={header i
nteger}
\n
"
+
in
:
"{.section
P
data }
\n
"
+
"{
Header|uppercase}={Integer H
eader|multiword}
\n
"
+
"{
Header|html}={Header I
nteger|multiword}
\n
"
+
"{
Header|html}={Header I
nteger}
\n
"
+
"{.end}
\n
"
,
out
:
"HEADER=<77><Header>
\n
"
+
...
...
@@ -335,29 +336,29 @@ var tests = []*Test{
},
&
Test
{
in
:
"{
r
aw}
\n
"
+
"{
r
aw|html}
\n
"
,
in
:
"{
R
aw}
\n
"
+
"{
R
aw|html}
\n
"
,
out
:
"&<>!@ #$%^
\n
"
+
"&<>!@ #$%^
\n
"
,
},
&
Test
{
in
:
"{.section
e
mptystring}emptystring{.end}
\n
"
+
"{.section
h
eader}header{.end}
\n
"
,
in
:
"{.section
E
mptystring}emptystring{.end}
\n
"
+
"{.section
H
eader}header{.end}
\n
"
,
out
:
"
\n
header
\n
"
,
},
&
Test
{
in
:
"{.section
t
rue}1{.or}2{.end}
\n
"
+
"{.section
f
alse}3{.or}4{.end}
\n
"
,
in
:
"{.section
T
rue}1{.or}2{.end}
\n
"
+
"{.section
F
alse}3{.or}4{.end}
\n
"
,
out
:
"1
\n
4
\n
"
,
},
&
Test
{
in
:
"{
b
ytes}"
,
in
:
"{
B
ytes}"
,
out
:
"hello"
,
},
...
...
@@ -365,32 +366,32 @@ var tests = []*Test{
// Maps
&
Test
{
in
:
"{
m
p.mapkey}
\n
"
,
in
:
"{
M
p.mapkey}
\n
"
,
out
:
"Ahoy!
\n
"
,
},
&
Test
{
in
:
"{
innermap.m
p.innerkey}
\n
"
,
in
:
"{
Innermap.M
p.innerkey}
\n
"
,
out
:
"55
\n
"
,
},
&
Test
{
in
:
"{.section
innermap}{.section m
p}{innerkey}{.end}{.end}
\n
"
,
in
:
"{.section
Innermap}{.section M
p}{innerkey}{.end}{.end}
\n
"
,
out
:
"55
\n
"
,
},
&
Test
{
in
:
"{.section
json
}{.repeated section maps}{a}{b}{.end}{.end}
\n
"
,
in
:
"{.section
JSON
}{.repeated section maps}{a}{b}{.end}{.end}
\n
"
,
out
:
"1234
\n
"
,
},
&
Test
{
in
:
"{
s
tringmap.stringkey1}
\n
"
,
in
:
"{
S
tringmap.stringkey1}
\n
"
,
out
:
"stringresult
\n
"
,
},
&
Test
{
in
:
"{.repeated section
s
tringmap}
\n
"
+
in
:
"{.repeated section
S
tringmap}
\n
"
+
"{@}
\n
"
+
"{.end}"
,
...
...
@@ -398,7 +399,7 @@ var tests = []*Test{
"stringresult
\n
"
,
},
&
Test
{
in
:
"{.repeated section
s
tringmap}
\n
"
+
in
:
"{.repeated section
S
tringmap}
\n
"
+
"
\t
{@}
\n
"
+
"{.end}"
,
...
...
@@ -409,22 +410,22 @@ var tests = []*Test{
// Interface values
&
Test
{
in
:
"{
i
face}"
,
in
:
"{
I
face}"
,
out
:
"[1 2 3]"
,
},
&
Test
{
in
:
"{.repeated section
i
face}{@}{.alternates with} {.end}"
,
in
:
"{.repeated section
I
face}{@}{.alternates with} {.end}"
,
out
:
"1 2 3"
,
},
&
Test
{
in
:
"{.section
i
face}{@}{.end}"
,
in
:
"{.section
I
face}{@}{.end}"
,
out
:
"[1 2 3]"
,
},
&
Test
{
in
:
"{.section
ifaceptr}{item} {v
alue}{.end}"
,
in
:
"{.section
Ifaceptr}{Item} {V
alue}{.end}"
,
out
:
"Item Value"
,
},
...
...
@@ -457,30 +458,30 @@ func TestAll(t *testing.T) {
func
testAll
(
t
*
testing
.
T
,
parseFunc
func
(
*
Test
)
(
*
Template
,
os
.
Error
))
{
s
:=
new
(
S
)
// initialized by hand for clarity.
s
.
h
eader
=
"Header"
s
.
i
nteger
=
77
s
.
r
aw
=
"&<>!@ #$%^"
s
.
i
nnerT
=
t1
s
.
d
ata
=
[]
T
{
t1
,
t2
}
s
.
p
data
=
[]
*
T
{
&
t1
,
&
t2
}
s
.
e
mpty
=
[]
*
T
{}
s
.
n
ull
=
nil
s
.
v
ec
=
new
(
vector
.
Vector
)
s
.
v
ec
.
Push
(
"elt1"
)
s
.
v
ec
.
Push
(
"elt2"
)
s
.
t
rue
=
true
s
.
f
alse
=
false
s
.
m
p
=
make
(
map
[
string
]
string
)
s
.
m
p
[
"mapkey"
]
=
"Ahoy!"
json
.
Unmarshal
([]
byte
(
`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`
),
&
s
.
json
)
s
.
innermap
.
m
p
=
make
(
map
[
string
]
int
)
s
.
innermap
.
m
p
[
"innerkey"
]
=
55
s
.
s
tringmap
=
make
(
map
[
string
]
string
)
s
.
s
tringmap
[
"stringkey1"
]
=
"stringresult"
// the same value so repeated section is order-independent
s
.
s
tringmap
[
"stringkey2"
]
=
"stringresult"
s
.
b
ytes
=
[]
byte
(
"hello"
)
s
.
i
face
=
[]
int
{
1
,
2
,
3
}
s
.
i
faceptr
=
&
T
{
"Item"
,
"Value"
}
s
.
H
eader
=
"Header"
s
.
I
nteger
=
77
s
.
R
aw
=
"&<>!@ #$%^"
s
.
I
nnerT
=
t1
s
.
D
ata
=
[]
T
{
t1
,
t2
}
s
.
P
data
=
[]
*
T
{
&
t1
,
&
t2
}
s
.
E
mpty
=
[]
*
T
{}
s
.
N
ull
=
nil
s
.
V
ec
=
new
(
vector
.
Vector
)
s
.
V
ec
.
Push
(
"elt1"
)
s
.
V
ec
.
Push
(
"elt2"
)
s
.
T
rue
=
true
s
.
F
alse
=
false
s
.
M
p
=
make
(
map
[
string
]
string
)
s
.
M
p
[
"mapkey"
]
=
"Ahoy!"
json
.
Unmarshal
([]
byte
(
`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`
),
&
s
.
JSON
)
s
.
Innermap
.
M
p
=
make
(
map
[
string
]
int
)
s
.
Innermap
.
M
p
[
"innerkey"
]
=
55
s
.
S
tringmap
=
make
(
map
[
string
]
string
)
s
.
S
tringmap
[
"stringkey1"
]
=
"stringresult"
// the same value so repeated section is order-independent
s
.
S
tringmap
[
"stringkey2"
]
=
"stringresult"
s
.
B
ytes
=
[]
byte
(
"hello"
)
s
.
I
face
=
[]
int
{
1
,
2
,
3
}
s
.
I
faceptr
=
&
T
{
"Item"
,
"Value"
}
var
buf
bytes
.
Buffer
for
_
,
test
:=
range
tests
{
...
...
@@ -606,10 +607,10 @@ func TestCustomDelims(t *testing.T) {
func
TestVarIndirection
(
t
*
testing
.
T
)
{
s
:=
new
(
S
)
// initialized by hand for clarity.
s
.
i
nnerPointerT
=
&
t1
s
.
I
nnerPointerT
=
&
t1
var
buf
bytes
.
Buffer
input
:=
"{.section @}{
i
nnerPointerT}{.end}"
input
:=
"{.section @}{
I
nnerPointerT}{.end}"
tmpl
,
err
:=
Parse
(
input
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
"unexpected parse error:"
,
err
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment