Add embed-directive example (#423)

* Add embed-directive example and rename embedding to struct-embedding

Signed-off-by: peterzhu1992 <peterzhu1992@gmail.com>

* Minor tweaks

Signed-off-by: peterzhu1992 <peterzhu1992@gmail.com>

* Add some improvements

Signed-off-by: peterzhu1992 <peterzhu1992@gmail.com>

* Add isDir() checks for measure.go and generate.go in tools

Signed-off-by: peterzhu1992 <peterzhu1992@gmail.com>
This commit is contained in:
peterzhu1992 2022-05-24 08:31:13 -04:00 committed by GitHub
parent a19c5b87e6
commit 7e4533640b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 326 additions and 19 deletions

View File

@ -65,6 +65,7 @@ Line Filters
File Paths
Directories
Temporary Files and Directories
Embed Directive
Testing and Benchmarking
Command-Line Arguments
Command-Line Flags

View File

@ -0,0 +1,45 @@
// `//go:embed` is a compiler directive that allows programs to include arbitrary
// files/folders in the binary. Read more about go directive
// [here](https://dave.cheney.net/2018/01/08/gos-hidden-pragmas).
package main
// If no exported identifiers is directly used from `embed` package,
// you can add an underscore `_` before the package name. In this example, we simply
// import it as we need to use the `embed.FS` type from the package.
import (
//_ "embed"
"embed"
)
// Since one file is defined after the directive, the compiler will only include
// this single file, followed by variable `single_file_string` to access as `string` type.
//go:embed example_folder/single_file.txt
var single_file_string string
// Here is a similar example but include single file as `[]byte`.
//go:embed example_folder/single_file.txt
var single_file_byte []byte
// We can also embed multiple files or even folders with wildcard.
//go:embed example_folder/single_file.txt
//go:embed example_folder/*.hash
var folder_FS embed.FS
func main() {
// Print out content of `example_single_file.txt` as `string`.
print(single_file_string)
// Now handle `[]byte`.
print(string(single_file_byte))
// Retrieve file(s) matching `*.hash` pattern by reading from variable `folder_FS` first,
// then print out.
hash_file1 := "example_folder/multi_file1.hash"
hash_file2 := "example_folder/multi_file2.hash"
hash_content1, _ := folder_FS.ReadFile(hash_file1)
hash_content2, _ := folder_FS.ReadFile(hash_file2)
print(string(hash_content1))
print(string(hash_content2))
}

View File

@ -0,0 +1,2 @@
e996755d889f01c99c353616fb2bdeac6c3be6e6
-EXJc75EbN-

View File

@ -0,0 +1,14 @@
# Use these commands to run the example.
# (Note: due to limitation on go playground,
# this example can only be run on your local machine.)
$ mkdir -p example_folder
$ echo "hello go" > example_folder/single_file.txt
$ echo "123" > example_folder/multi_file1.hash
$ echo "456" > example_folder/multi_file2.hash
$ go run embed-directive.go
hello go
hello go
123
456

View File

@ -0,0 +1 @@
123

View File

@ -0,0 +1 @@
456

View File

@ -0,0 +1 @@
hello go

226
public/embed-directive generated Normal file
View File

@ -0,0 +1,226 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Go by Example: Embed Directive</title>
<link rel=stylesheet href="site.css">
</head>
<script>
onkeydown = (e) => {
if (e.key == "ArrowLeft") {
window.location.href = 'temporary-files-and-directories';
}
if (e.key == "ArrowRight") {
window.location.href = 'testing-and-benchmarking';
}
}
</script>
<body>
<div class="example" id="embed-directive">
<h2><a href="./">Go by Example</a>: Embed Directive</h2>
<table>
<tr>
<td class="docs">
<p><code>//go:embed</code> is a compiler directive that allows programs to include arbitrary
files/folders in the binary. Read more about go directive
<a href="https://dave.cheney.net/2018/01/08/gos-hidden-pragmas">here</a>.</p>
</td>
<td class="code leading">
<a href="http://play.golang.org/p/-EXJc75EbN-"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
<pre class="chroma">
<span class="kn">package</span> <span class="nx">main</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>If no exported identifiers is directly used from <code>embed</code> package,
you can add an underscore <code>_</code> before the package name. In this example, we simply
import it as we need to use the <code>embed.FS</code> type from the package.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="kn">import</span> <span class="p">(</span>
<span class="c1">//_ &#34;embed&#34;
</span><span class="c1"></span> <span class="s">&#34;embed&#34;</span>
<span class="p">)</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Since one file is defined after the directive, the compiler will only include
this single file, followed by variable <code>single_file_string</code> to access as <code>string</code> type.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="c1">//go:embed example_folder/single_file.txt
</span><span class="c1"></span><span class="kd">var</span> <span class="nx">single_file_string</span> <span class="kt">string</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Here is a similar example but include single file as <code>[]byte</code>.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="c1">//go:embed example_folder/single_file.txt
</span><span class="c1"></span><span class="kd">var</span> <span class="nx">single_file_byte</span> <span class="p">[]</span><span class="kt">byte</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>We can also embed multiple files or even folders with wildcard.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="c1">//go:embed example_folder/single_file.txt
</span><span class="c1">//go:embed example_folder/*.hash
</span><span class="c1"></span><span class="kd">var</span> <span class="nx">folder_FS</span> <span class="nx">embed</span><span class="p">.</span><span class="nx">FS</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Print out content of <code>example_single_file.txt</code> as <code>string</code>.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="nb">print</span><span class="p">(</span><span class="nx">single_file_string</span><span class="p">)</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Now handle <code>[]byte</code>.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="nb">print</span><span class="p">(</span><span class="nb">string</span><span class="p">(</span><span class="nx">single_file_byte</span><span class="p">))</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Retrieve file(s) matching <code>*.hash</code> pattern by reading from variable <code>folder_FS</code> first,
then print out.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="nx">hash_file1</span> <span class="o">:=</span> <span class="s">&#34;example_folder/multi_file1.hash&#34;</span>
<span class="nx">hash_file2</span> <span class="o">:=</span> <span class="s">&#34;example_folder/multi_file2.hash&#34;</span>
<span class="nx">hash_content1</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">folder_FS</span><span class="p">.</span><span class="nf">ReadFile</span><span class="p">(</span><span class="nx">hash_file1</span><span class="p">)</span>
<span class="nx">hash_content2</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">folder_FS</span><span class="p">.</span><span class="nf">ReadFile</span><span class="p">(</span><span class="nx">hash_file2</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">string</span><span class="p">(</span><span class="nx">hash_content1</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">string</span><span class="p">(</span><span class="nx">hash_content2</span><span class="p">))</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code">
<pre class="chroma"><span class="p">}</span>
</pre>
</td>
</tr>
</table>
<table>
<tr>
<td class="docs">
<p>Use these commands to run the example.
(Note: due to limitation on go playground,
this example can only be run on your local machine.)</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="gp">$</span> mkdir -p example_folder
<span class="gp">$</span> echo &#34;hello go&#34; &gt; example_folder/single_file.txt
<span class="gp">$</span> echo &#34;123&#34; &gt; example_folder/multi_file1.hash
<span class="gp">$</span> echo &#34;456&#34; &gt; example_folder/multi_file2.hash</pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code">
<pre class="chroma"><span class="gp">$</span> go run embed-directive.go
<span class="go">hello go
</span><span class="go">hello go
</span><span class="go">123
</span><span class="go">456</span></pre>
</td>
</tr>
</table>
<p class="next">
Next example: <a href="testing-and-benchmarking">Testing and Benchmarking</a>.
</p>
<p class="footer">
by <a href="https://markmcgranaghan.com">Mark McGranaghan</a> and <a href="https://eli.thegreenplace.net">Eli Bendersky</a> | <a href="https://github.com/mmcgrana/gobyexample">source</a> | <a href="https://github.com/mmcgrana/gobyexample#license">license</a>
</p>
</div>
<script>
var codeLines = [];
codeLines.push('package main\u000A');codeLines.push('import (\u000A //_ \"embed\"\u000A \"embed\"\u000A)\u000A');codeLines.push('//go:embed example_folder/single_file.txt\u000Avar single_file_string string\u000A');codeLines.push('//go:embed example_folder/single_file.txt\u000Avar single_file_byte []byte\u000A');codeLines.push('//go:embed example_folder/single_file.txt\u000A//go:embed example_folder/*.hash\u000Avar folder_FS embed.FS\u000A');codeLines.push('func main() {\u000A');codeLines.push(' print(single_file_string)\u000A');codeLines.push(' print(string(single_file_byte))\u000A');codeLines.push(' hash_file1 :\u003D \"example_folder/multi_file1.hash\"\u000A hash_file2 :\u003D \"example_folder/multi_file2.hash\"\u000A hash_content1, _ :\u003D folder_FS.ReadFile(hash_file1)\u000A hash_content2, _ :\u003D folder_FS.ReadFile(hash_file2)\u000A print(string(hash_content1))\u000A print(string(hash_content2))\u000A');codeLines.push('}\u000A');codeLines.push('');codeLines.push('');
</script>
<script src="site.js" async></script>
</body>
</html>

2
public/index.html generated
View File

@ -161,6 +161,8 @@
<li><a href="temporary-files-and-directories">Temporary Files and Directories</a></li>
<li><a href="embed-directive">Embed Directive</a></li>
<li><a href="testing-and-benchmarking">Testing and Benchmarking</a></li>
<li><a href="command-line-arguments">Command-Line Arguments</a></li>

View File

@ -14,7 +14,7 @@
if (e.key == "ArrowRight") {
window.location.href = 'testing-and-benchmarking';
window.location.href = 'embed-directive';
}
}
@ -225,7 +225,7 @@ prefixing them with our temporary directory.</p>
<p class="next">
Next example: <a href="testing-and-benchmarking">Testing and Benchmarking</a>.
Next example: <a href="embed-directive">Embed Directive</a>.
</p>

View File

@ -9,7 +9,7 @@
onkeydown = (e) => {
if (e.key == "ArrowLeft") {
window.location.href = 'temporary-files-and-directories';
window.location.href = 'embed-directive';
}

View File

@ -36,6 +36,11 @@ func check(err error) {
}
}
func isDir(path string) bool {
fileStat, _ := os.Stat(path)
return fileStat.IsDir()
}
func ensureDir(dir string) {
err := os.MkdirAll(dir, 0755)
check(err)
@ -275,14 +280,16 @@ func parseExamples() []*Example {
example.Segs = make([][]*Seg, 0)
sourcePaths := mustGlob("examples/" + exampleID + "/*")
for _, sourcePath := range sourcePaths {
if strings.HasSuffix(sourcePath, ".hash") {
example.GoCodeHash, example.URLHash = parseHashFile(sourcePath)
} else {
sourceSegs, filecontents := parseAndRenderSegs(sourcePath)
if filecontents != "" {
example.GoCode = filecontents
if ! isDir(sourcePath) {
if strings.HasSuffix(sourcePath, ".hash") {
example.GoCodeHash, example.URLHash = parseHashFile(sourcePath)
} else {
sourceSegs, filecontents := parseAndRenderSegs(sourcePath)
if filecontents != "" {
example.GoCode = filecontents
}
example.Segs = append(example.Segs, sourceSegs)
}
example.Segs = append(example.Segs, sourceSegs)
}
}
newCodeHash := sha1Sum(example.GoCode)

View File

@ -21,6 +21,11 @@ func readLines(path string) []string {
return strings.Split(string(srcBytes), "\n")
}
func isDir(path string) bool {
fileStat, _ := os.Stat(path)
return fileStat.IsDir()
}
var commentPat = regexp.MustCompile("\\s*\\/\\/")
func main() {
@ -29,15 +34,17 @@ func main() {
foundLongFile := false
for _, sourcePath := range sourcePaths {
foundLongLine := false
lines := readLines(sourcePath)
for i, line := range lines {
// Convert tabs to spaces before measuring, so we get an accurate measure
// of how long the output will end up being.
line := strings.Replace(line, "\t", " ", -1)
if !foundLongLine && !commentPat.MatchString(line) && (utf8.RuneCountInString(line) > 58) {
fmt.Printf("measure: %s:%d\n", sourcePath, i+1)
foundLongLine = true
foundLongFile = true
if ! isDir(sourcePath) {
lines := readLines(sourcePath)
for i, line := range lines {
// Convert tabs to spaces before measuring, so we get an accurate measure
// of how long the output will end up being.
line := strings.Replace(line, "\t", " ", -1)
if !foundLongLine && !commentPat.MatchString(line) && (utf8.RuneCountInString(line) > 58) {
fmt.Printf("measure: %s:%d\n", sourcePath, i+1)
foundLongLine = true
foundLongFile = true
}
}
}
}