文档章节

把代码执行演示嵌在你的PPT中

naughty
 naughty
发布于 2017/09/06 20:15
字数 1345
阅读 1786
收藏 51

“Talk is cheap, show me your code!”

当一个程序员在做技术分享的时候, 代码演示经常是不可或缺的一个环节。然而在你的演示PPT和代码运行之间切换是一件非常恼人事情,而且非常影响演示的节奏和流畅性。要做一个完美的技术分享,能不能把代码的运行嵌入到PPT中呢?

当然可以,我前不久在公司内部分享了一起关于Python的小谜题,大家可以到斗鱼去观看这次分享的视频录播 (很糟糕的是在36分钟后,摄像头偏移了,拍了大半天挂钟)

为了实现代码嵌入ppt,我用到的关键技术包括:

首先,演示常用的是微软的PowerPoint(至于苹果的Keynote,我暂时还没有找到解决方案),所以你需要安装PowerPoint,在最新的Office套件中,微软提供了一个Webview的插件,有了这个插件,可以直接把一个Web页面,嵌入到Office文档中,自然也就包含了PPT。

注意,为了安全性的考虑,嵌入的web页面必须是https的。

好了有了这个,我们就可以把一个代码运行的web页面直接嵌入到演示文档中,剩下的事情,就是做一个可以运行不同代码的Web应用了。

Glot 是一个开源的在线代码运行平台。其架构如下图所示。

利用Glot的代码运行的核心功能,我们就可以很方便的开发一个可以运行各种代码的web应用。

利用容器,我们可以把整个应用分为以下的几个层次:

  • Base
    提供基本的代码运行的环境,包含了代码执行的必要的解释器和编译器。在本次演示中,我使用了golang:latest,但是碰巧的是这个镜像是拥有Python的解释器的,我的代码演示都是python,省去了我安装Python的步骤。如果是别的不同的语言的演示,注意安装对应的环境。
  • Code Runner https://github.com/gangtao/code_runner
    我的Code Runner是对Glot的Code Runner的一个增强,该项目提供一个运行代码的服务。
    项目的Dockerfile:
    FROM golang:latest
    
    MAINTAINER gangtao@outlook.com
    
    ENV GOPATH=/home/glot
    ENV GOROOT=/usr/local/go
    
    # Add user
    RUN groupadd glot
    RUN useradd -m -d /home/glot -g glot -s /bin/bash glot
    
    # Copy files
    Add ./build/release/server /home/glot/
    # Add ./vendor/. /home/glot/src
    
    USER glot
    WORKDIR /home/glot/
    
    # generate certificate
    RUN go run $GOROOT/src/crypto/tls/generate_cert.go --host localhost
    
    EXPOSE 8080
    
    # CMD ["/home/glot/runner"]
    ENTRYPOINT ["/home/glot/server"]
    通过Dockerfile我们可以看出该项目主要的内容:利用Glot实现代码运行,产生证书用于https,利用echo实现web 服务。
    Web服务的代码如下:
    package code_runner
    
    import (
    	"fmt"
    	"github.com/prasmussen/glot-code-runner/cmd"
    	"github.com/prasmussen/glot-code-runner/language"
    	"io/ioutil"
    	"os"
    	"path/filepath"
    )
    
    type Payload struct {
    	Language string          `json:"language"`
    	Files    []*InMemoryFile `json:"files"`
    	Stdin    string          `json:"stdin"`
    	Command  string          `json:"command"`
    }
    
    type InMemoryFile struct {
    	Name    string `json:"name"`
    	Content string `json:"content"`
    }
    
    type Result struct {
    	Stdout string `json:"stdout"`
    	Stderr string `json:"stderr"`
    	Error  string `json:"error"`
    }
    
    func Run(payload *Payload) *Result {
    	// Ensure that we have at least one file
    	if len(payload.Files) == 0 {
    		exitF("No files given\n")
    	}
    
    	// Check if we support given language
    	if !language.IsSupported(payload.Language) {
    		exitF("Language '%s' is not supported\n", payload.Language)
    	}
    
    	// Write files to disk
    	filepaths, err := writeFiles(payload.Files)
    	if err != nil {
    		exitF("Failed to write file to disk (%s)", err.Error())
    	}
    
    	var stdout, stderr string
    
    	// Execute the given command or run the code with
    	// the language runner if no command is given
    	if payload.Command == "" {
    		stdout, stderr, err = language.Run(payload.Language, filepaths, payload.Stdin)
    	} else {
    		workDir := filepath.Dir(filepaths[0])
    		stdout, stderr, err = cmd.RunBashStdin(workDir, payload.Command, payload.Stdin)
    	}
    
    	result := &Result{
    		Stdout: stdout,
    		Stderr: stderr,
    		Error:  errToStr(err),
    	}
    
    	return result
    }
    
    // Writes files to disk, returns list of absolute filepaths
    func writeFiles(files []*InMemoryFile) ([]string, error) {
    	// Create temp dir
    	tmpPath, err := ioutil.TempDir("", "")
    	if err != nil {
    		return nil, err
    	}
    
    	paths := make([]string, len(files), len(files))
    	for i, file := range files {
    		path, err := writeFile(tmpPath, file)
    		if err != nil {
    			return nil, err
    		}
    
    		paths[i] = path
    
    	}
    	return paths, nil
    }
    
    // Writes a single file to disk
    func writeFile(basePath string, file *InMemoryFile) (string, error) {
    	// Get absolute path to file inside basePath
    	absPath := filepath.Join(basePath, file.Name)
    
    	// Create all parent dirs
    	err := os.MkdirAll(filepath.Dir(absPath), 0775)
    	if err != nil {
    		return "", err
    	}
    
    	// Write file to disk
    	err = ioutil.WriteFile(absPath, []byte(file.Content), 0664)
    	if err != nil {
    		return "", err
    	}
    
    	// Return absolute path to file
    	return absPath, nil
    }
    
    func exitF(format string, a ...interface{}) {
    	fmt.Fprintf(os.Stderr, format, a...)
    	os.Exit(1)
    }
    
    func errToStr(err error) string {
    	if err != nil {
    		return err.Error()
    	}
    
    	return ""
    }

    可以通过容器方便的启动该服务,然后就可以通过Rest请求,执行Python(Golang)的代码。
  • curl \
      -X POST \
      http://localhost:8080/run \
      -H 'Content-Type: application/json' \
      -d '{"language":"python","files":[{"name":"main.py","content":"print(42)"}]}'
    
    {"stdout":"42\n","stderr":"","error":""}

    在这个项目中,我用了echo来实现一个轻量级的Web服务,而没有使用Glot自带的基于Ruby的服务,这样做的好处是技术栈的统一,因为echo和glot的核心都是用的Golang。

  • Code Runner Web https://github.com/gangtao/code_runner_web
    有了服务,下面就是前端的UI了。
    UI使用了codemirror来做编辑器。Dockerfile如下:
    FROM naughtytao/code_runner
    
    MAINTAINER gangtao@outlook.com
    
    Add ./static /home/glot/static

    运行Code Runner Web后,就可以在以下的web界面中输入你想要运行的结果,并实时的显示想要运行的结果了。

好了,剩下的还有一些事情要做,就是准备你的演示代码,大家可以参考这个项目,这里缺省是将所有的代码片段放在code/python/ 目录下。运行:http://localhost:8080/#2 就会加载第二个代码片段。

这个是嵌入后的效果:

好了,是不是很Coooooool呢?

另外利用容器来构建应用真的非常非常方便。

© 著作权归作者所有

naughty

naughty

粉丝 339
博文 70
码字总数 136968
作品 0
其它
私信 提问
加载中

评论(5)

naughty
naughty

引用来自“绫小路清隆”的评论

访问什么网站都可以吗?wps有这个吗?
WPS恐怕没有,需要支持https
开源中国首席罗纳尔多
开源中国首席罗纳尔多
访问什么网站都可以吗?wps有这个吗?
bug0day
bug0day
不错 收藏
一个成为架构师的男人
厉害��
Blackshao
Blackshao
66666666666
网络幻灯片--nodePPT

nodePPT 是使用nodejs写的网络幻灯片。 为什么选择nodePPT 基于GFM的markdown语法编写 支持html混排,再复杂的demo也可以做! 导出网页或者pdf更容易分享 支持18种转场动画,可以设置单页动画...

叶秀兰
2014/07/29
4.1K
1
如何在 PPT 里面演示动态图表?

每次在我介绍完 Excel 动态图表的做法之后,就会有人问到:“这个动态图表能不能放到 PPT 里面演示呢?” 有的朋友甚至直接把 Excel 里的动态图表区域复制粘贴到 PPT 里,期望 PPT 里也能有动...

刘万祥ExcelPro
2017/03/01
0
0
基于docker+reveal.js搭建一个属于自己的在线ppt网站

前言 最近热衷于,由于这段时间使用来折腾自己的服务器,越来越感觉这是一种极其被应该推广的技术,因此想在公司内部也做一次技术分享。当然,如果只是做的PPT,我就不写这文章了。既然把说这...

无上@诀
2017/11/28
0
0
累死累活干不过做 PPT 的!

2019年年会最火的莫过于新东方年会,既然累死累活干不过做PPT,那么我们就要写好PPT。 nodeppt就是帮助大家用markdown语法来快速创建一个高大上的在线演示文档。 先来看看效果:js8.in/node...

三水清
02/23
0
0
使用 Pascal 脚本编写网页

为了不显得那么"深奥",作者打算将Pascal服务器页面(PSP)作为一个动态网页,并且嵌入Pascal脚本代码。当页面接到客户端的反馈时,Pascal脚本代码会在服务器内部执行(准确的来说应该是经过解释...

oschina
2012/12/18
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

linux高级文件数据操作

cat :显示切割数据 -f:选择显示切割列; -s:比现实没有分割的行 -d:自定义分隔符 cut -d ‘ ’-f 1,3 a.txt : 以空格为分隔符显示第一列和第三列;这种情况不能分隔的行也会显示出来,如...

为何不可1995
28分钟前
1
0
在Javascript中Eval函数的使用

【eval()函数】 JavaScript有许多小窍门来使编程更加容易。 其中之一就是eval()函数,这个函数可以把一个字符串当作一个JavaScript表达式一样去执行它。 举个小例子: var the_unevaled_ans...

花漾年华
40分钟前
3
0
[日更-2019.5.22、23] Android 系统的分区和文件系统(二)--Android 文件系统中的文件

声明 Android系统中有很多分区,每个分区内的文件系统一般都不同的,使用ADB进入系统/目录下可发现挂载这很多的目录,不同的目录中可来自不同的分区及文件系统; 那么,就来分下这些目录里面...

小馬佩德罗
44分钟前
2
0
数组操作相关算法

/*数组的相关的算法操作:1、在数组中找最大值/最小值*/class Test11_FindMax{public static void main(String[] args){int[] array = {4,2,6,8,1};//在数组中找最大...

architect刘源源
今天
4
0
okhttp3 以上版本在安卓9.0无法请求数据的解决方案

应用官方的说明:在 Android 6.0 中,我们取消了对 Apache HTTP 客户端的支持。 从 Android 9 开始,默认情况下该内容库已从 bootclasspath 中移除且不可用于应用。且Android P 限制了明文流量...

chenhongjiang
今天
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部