beamlet 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 266bc21197b4454a0bf0c7c347e4a6649bd070d46362f031f9b283a245887128
4
+ data.tar.gz: c51fdd34c879e63a8e0d67f8cf5430eb9e7a554cd1ad1c4f2279822be6475203
5
+ SHA512:
6
+ metadata.gz: a268426e495feea790f8912f3c3fac560ffda4ea51071ffc3c155efb66a7c218a8795acddea6203d142eb9cb9eedc3875916bf899d828197783842cbd34f8a03
7
+ data.tar.gz: 1df6b58f65ab93ef981429a6963af15647e168507bdbb1e7b8467343607815f1a6254945d92a98eaeb03c8b6573725bdf1fbf869d3e69736813664007f536875
data/README.md ADDED
File without changes
data/bin/beamlet ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "beamlet"
5
+ Beamlet::CLI.run(ARGV)
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+
5
+ module Beamlet
6
+ class CLI
7
+ def self.run(argv)
8
+ opts = parse(argv)
9
+ gen = Generator.new(opts)
10
+
11
+ out = case opts[:mode]
12
+ when :document then gen.document
13
+ when :frame then gen.frame
14
+ when :part then gen.part
15
+ else
16
+ warn "Rien à générer. Essayez beamlet --help"
17
+ return 1
18
+ end
19
+
20
+ puts out
21
+ 0
22
+ end
23
+
24
+ def self.parse(argv)
25
+ opts = { mode: nil, items: [], enum_items: [] }
26
+
27
+ parser = OptionParser.new do |o|
28
+ o.banner = "Usage: beamlet [options]"
29
+
30
+ o.on("-d", "--document", "Generate top-level document") do
31
+ opts[:mode] = :document
32
+ end
33
+ o.on("-f", "--frame", "Generate a frame") do
34
+ opts[:mode] = :frame
35
+ end
36
+
37
+ o.on("-T", "--title TITLE", "Document title") { |v| opts[:title] = v }
38
+ o.on("-a", "--author AUTHOR", "Author") { |v| opts[:author] = v }
39
+ o.on("-i", "--date DATE", "Date") { |v| opts[:date] = v }
40
+ o.on("--theme THEME", "Beamer theme (default Madrid)") { |v| opts[:theme] = v }
41
+ o.on("--[no-]titleframe", "Include title frame") { |v| opts[:titleframe] = v }
42
+ o.on("-P", "--part", "Generate a part slide") do
43
+ opts[:mode] = :part
44
+ end
45
+ o.on("-p", "--part-title TITLE", "Part title") { |v| opts[:part_title] = v }
46
+ o.on("-t", "--frame-title TITLE", "Frame title") { |v| opts[:frame_title] = v }
47
+ o.on("-s", "--splits N", Integer, "Split frame vertically into N columns") do |v|
48
+ opts[:splits] = v
49
+ end
50
+ o.on("--fragile", "Mark frame as fragile (for verbatim/code)") { opts[:fragile] = true }
51
+ o.on("--allowframebreaks", "Allow frame breaks") { opts[:allowframebreaks] = true }
52
+
53
+ o.on("-l", "--itemize A,B,C", Array, "Itemize list (left by default)") do |v|
54
+ opts[:items] = v
55
+ end
56
+ o.on("-e", "--enumerate A,B,C", Array, "Enumerate list") do |v|
57
+ opts[:enum_items] = v
58
+ end
59
+ o.on("-b", "--block TITLE", "Add a standard block") do |v|
60
+ opts[:block_kind] = "block"
61
+ opts[:block_title] = v
62
+ opts[:block_body] = STDIN.tty? ? "contenu..." : $stdin.read.chomp
63
+ end
64
+ o.on("-A", "--alert TITLE", "Add an alertblock") do |v|
65
+ opts[:block_kind] = "alertblock"
66
+ opts[:block_title] = v
67
+ opts[:block_body] = STDIN.tty? ? "attention !" : $stdin.read.chomp
68
+ end
69
+ o.on("-E", "--example TITLE", "Add an exampleblock") do |v|
70
+ opts[:block_kind] = "exampleblock"
71
+ opts[:block_title] = v
72
+ opts[:block_body] = STDIN.tty? ? "exemple..." : $stdin.read.chomp
73
+ end
74
+
75
+ o.on("-I", "--image FILE", "Insert image") { |v| opts[:image_file] = v }
76
+ o.on("--image-opts OPTS", "Image options (default width=0.8\\textwidth)") do |v|
77
+ opts[:image_opts] = v
78
+ end
79
+ o.on("-c", "--code LANG", "Code listing (body from stdin)") do |v|
80
+ opts[:code_lang] = v
81
+ opts[:code_body] = STDIN.tty? ? "# code" : $stdin.read.chomp
82
+ opts[:fragile] = true
83
+ end
84
+ o.on("-p", "--pause", "Insert \\pause") { opts[:pause] = true }
85
+ o.on("-n", "--note TEXT", "Speaker note") { |v| opts[:note_body] = v }
86
+
87
+ o.on("-h", "--help", "Show help") { puts o; exit 0 }
88
+ o.on("-v", "--version", "Show version") { puts Beamlet::VERSION; exit 0 }
89
+ end
90
+
91
+ parser.parse!(argv)
92
+ opts
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Beamlet
4
+ class Generator
5
+ def initialize(opts = {})
6
+ @opts = default_opts.merge(opts)
7
+ end
8
+
9
+ def document
10
+ titleframe = @opts[:titleframe] ? Templates::TITLE_FRAME : ""
11
+ Templates::DOCUMENT % {
12
+ theme: @opts[:theme],
13
+ title: escape(@opts[:title]),
14
+ author: escape(@opts[:author]),
15
+ date: escape(@opts[:date]),
16
+ titleframe: titleframe,
17
+ body: "% --- vos frames ici ---"
18
+ }
19
+ end
20
+
21
+ def part
22
+ Templates::PART % {
23
+ title: escape(@opts[:part_title] || "Partie")
24
+ }
25
+ end
26
+
27
+ def frame
28
+ body = build_body
29
+ body = split_into_columns(body, @opts[:splits]) if @opts[:splits] && @opts[:splits] > 1
30
+
31
+ options = []
32
+ options << "fragile" if @opts[:fragile]
33
+ options << "allowframebreaks" if @opts[:allowframebreaks]
34
+ opt_str = options.empty? ? "" : "[#{options.join(',')}]"
35
+
36
+ Templates::FRAME % {
37
+ options: opt_str,
38
+ title: escape(@opts[:frame_title] || ""),
39
+ body: indent(body, 2)
40
+ }
41
+ end
42
+
43
+ private
44
+
45
+ def default_opts
46
+ {
47
+ theme: "Madrid",
48
+ title: "Titre",
49
+ author: "Auteur",
50
+ date: "\\today",
51
+ titleframe: true,
52
+ splits: 1,
53
+ items: [],
54
+ enum_items: [],
55
+ block_kind: "block",
56
+ block_title: "",
57
+ block_body: "",
58
+ note_body: "",
59
+ image_file: "",
60
+ image_opts: "width=0.8\\textwidth",
61
+ code_lang: "ruby",
62
+ code_body: "",
63
+ fragile: false,
64
+ allowframebreaks: false,
65
+ pause: false
66
+ }
67
+ end
68
+
69
+ def build_body
70
+ parts = []
71
+
72
+ unless @opts[:items].empty?
73
+ parts << format_list(Templates::ITEMIZE, @opts[:items])
74
+ end
75
+
76
+ unless @opts[:enum_items].empty?
77
+ parts << format_list(Templates::ENUMERATE, @opts[:enum_items])
78
+ end
79
+
80
+ unless @opts[:block_body].empty?
81
+ parts << Templates::BLOCK % {
82
+ kind: @opts[:block_kind],
83
+ title: escape(@opts[:block_title]),
84
+ body: @opts[:block_body]
85
+ }
86
+ end
87
+
88
+ unless @opts[:image_file].empty?
89
+ parts << Templates::IMAGE % {
90
+ opts: @opts[:image_opts],
91
+ file: @opts[:image_file]
92
+ }
93
+ end
94
+
95
+ unless @opts[:code_body].empty?
96
+ parts << Templates::CODE % {
97
+ lang: @opts[:code_lang],
98
+ body: @opts[:code_body]
99
+ }
100
+ end
101
+
102
+ parts << Templates::PAUSE if @opts[:pause]
103
+
104
+ unless @opts[:note_body].empty?
105
+ parts << Templates::NOTE % { body: @opts[:note_body] }
106
+ end
107
+
108
+ parts.empty? ? "" : parts.join("\n\n")
109
+ end
110
+
111
+ def split_into_columns(body, n)
112
+ slices = body.split(/\n\n+/)
113
+ per_col = (slices.size.to_f / n).ceil
114
+ groups = slices.each_slice(per_col).to_a
115
+ groups << [] while groups.size < n
116
+
117
+ width = (1.0 / n).round(2)
118
+ out = [Templates::COLUMNS_OPEN]
119
+ groups.each do |g|
120
+ out << " " + Templates::COLUMN % { width: width }
121
+ g.each { |line| out << " " + line }
122
+ end
123
+ out << Templates::COLUMNS_CLOSE
124
+ out.join("\n")
125
+ end
126
+
127
+ def format_list(template, items)
128
+ rendered = items.map { |i| escape(i) }.join("\n \\item ")
129
+ template % { items: rendered }
130
+ end
131
+
132
+ def indent(str, n)
133
+ pad = " " * n
134
+ str.lines.map { |l| l.chomp.empty? ? l : pad + l }.join
135
+ end
136
+
137
+ def escape(s)
138
+ s.to_s.gsub("\\", '\textbackslash{}')
139
+ .gsub(/[&%$#_{}]/) { |m| "\\#{m}" }
140
+ .gsub("~", '\textasciitilde{}')
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Beamlet
4
+ module Templates
5
+ DOCUMENT = <<~'TEX'
6
+ \documentclass[10pt,aspectratio=169]{beamer}
7
+ \usetheme{%{theme}}
8
+ \useoutertheme{infolines} % Alternatively: infolines, miniframes, shadow, sidebar, smoothbars, smoothtree, split, tree
9
+ \usepackage[french]{babel}
10
+ \usepackage[utf8]{inputenc}
11
+ \usepackage[T1]{fontenc}
12
+ \usepackage{listings}
13
+ \usepackage{graphicx}
14
+
15
+ \title{%{title}}
16
+ \author{%{author}}
17
+ \date{%{date}}
18
+
19
+ \begin{document}
20
+ %{titleframe}
21
+ %{body}
22
+ \end{document}
23
+ TEX
24
+
25
+ PART = <<~'TEX'
26
+ \part{%{title}}
27
+ \frame{\partpage}
28
+ TEX
29
+
30
+ TITLE_FRAME = <<~'TEX'
31
+ \begin{frame}
32
+ \titlepage
33
+ \end{frame}
34
+ TEX
35
+
36
+ FRAME = <<~'TEX'
37
+ \begin{frame}%{options}
38
+ \frametitle{%{title}}
39
+ %{body}
40
+ \end{frame}
41
+ TEX
42
+
43
+ COLUMNS_OPEN = '\begin{columns}[T]'
44
+ COLUMNS_CLOSE = '\end{columns}'
45
+ COLUMN = '\column{%{width}\textwidth}'
46
+
47
+ ITEMIZE = <<~'TEX'
48
+ \begin{itemize}
49
+ \item %{items}
50
+ \end{itemize}
51
+ TEX
52
+
53
+ ENUMERATE = <<~'TEX'
54
+ \begin{enumerate}
55
+ \item %{items}
56
+ \end{enumerate}
57
+ TEX
58
+
59
+ BLOCK = <<~'TEX'
60
+ \begin{%{kind}}{%{title}}
61
+ %{body}
62
+ \end{%{kind}}
63
+ TEX
64
+
65
+ PAUSE = '\pause'
66
+
67
+ NOTE = <<~'TEX'
68
+ \note{%{body}}
69
+ TEX
70
+
71
+ IMAGE = <<~'TEX'
72
+ \begin{center}
73
+ \includegraphics[%{opts}]{%{file}}
74
+ \end{center}
75
+ TEX
76
+
77
+ CODE = <<~'TEX'
78
+ \begin{lstlisting}[language=%{lang}]
79
+ %{body}
80
+ \end{lstlisting}
81
+ TEX
82
+ end
83
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Beamlet
4
+ VERSION = "0.1.0"
5
+ end
data/lib/beamlet.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "beamlet/version"
4
+ require_relative "beamlet/templates"
5
+ require_relative "beamlet/generator"
6
+ require_relative "beamlet/cli"
7
+
8
+ module Beamlet
9
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: beamlet
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jean-Christophe Le Lann
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: A small CLI tool to emit Beamer frames, documents, columns, lists and
13
+ blocks.
14
+ executables:
15
+ - beamlet
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - bin/beamlet
21
+ - lib/beamlet.rb
22
+ - lib/beamlet/cli.rb
23
+ - lib/beamlet/generator.rb
24
+ - lib/beamlet/templates.rb
25
+ - lib/beamlet/version.rb
26
+ homepage: http://www.jcll.fr
27
+ licenses:
28
+ - MIT
29
+ metadata: {}
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '3.0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubygems_version: 3.6.7
45
+ specification_version: 4
46
+ summary: Generate LaTeX/Beamer snippets from the CLI
47
+ test_files: []