├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin └── cheatset ├── cheatset.gemspec └── lib ├── cheatset.rb └── cheatset ├── cli.rb ├── creator.rb ├── dsl ├── base.rb ├── category.rb ├── cheatsheet.rb ├── context.rb └── entry.rb ├── templates ├── .sass-cache │ └── c0630dfea9543a0a71b68aca4887e98819b89684 │ │ └── style.scssc ├── cheatset_resources │ ├── Open_Sans.woff │ ├── Open_Sans_Bold.woff │ ├── Open_Sans_Bold_Italic.woff │ ├── Open_Sans_Extrabold.woff │ ├── Open_Sans_Extrabold_Italic.woff │ ├── Open_Sans_Italic.woff │ ├── Open_Sans_Semibold.woff │ └── Open_Sans_Semibold_Italic.woff ├── style.css ├── style.scss └── template.haml └── version.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | *.codekit 4 | .bundle 5 | .config 6 | .yardoc 7 | Gemfile.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | lib/bundler/man 13 | pkg 14 | rdoc 15 | spec/reports 16 | test/tmp 17 | test/version_tmp 18 | tmp 19 | .sass-cache/ 20 | lib/cheatset/templates/template.html 21 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Florian Dütsch 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cheatset 2 | 3 | [](http://badge.fury.io/rb/cheatset) 4 | 5 | Generate your own cheat sheets as docsets for [Dash](http://kapeli.com/dash)! 6 | Use this simple command line tool and write your cheat sheets in an easy 7 | language (Ruby DSL). 8 | 9 | ## Installation 10 | 11 | $ sudo gem install cheatset 12 | 13 | Note: this requires the Xcode Command Line Tools to be installed. Install them using this: 14 | 15 | $ xcode-select --install 16 | 17 | ## Contributions 18 | 19 | If you make a useful cheat sheet, please [contribute it](https://github.com/Kapeli/cheatsheets#readme) to Dash. 20 | 21 | ## Usage 22 | 23 | Write a file (here `sample.rb`) containing your cheat sheet data, e.g.: 24 | 25 | ```ruby 26 | cheatsheet do 27 | title 'Sample' # Will be displayed by Dash in the docset list 28 | docset_file_name 'Sample' # Used for the filename of the docset 29 | keyword 'sample' # Used as the initial search keyword (listed in Preferences > Docsets) 30 | # resources 'resources_dir' # An optional resources folder which can contain images or anything else 31 | 32 | introduction 'My *awesome* cheat sheet' # Optional, can contain Markdown or HTML 33 | 34 | # A cheat sheet must consist of categories 35 | category do 36 | id 'Windows' # Must be unique and is used as title of the category 37 | 38 | entry do 39 | command 'CMD+N' # Optional 40 | command 'CMD+SHIFT+N' # Multiple commands are supported 41 | name 'Create window' # A short name, can contain Markdown or HTML 42 | notes 'Some notes' # Optional longer explanation, can contain Markdown or HTML 43 | end 44 | entry do 45 | command 'CMD+W' 46 | name 'Close window' 47 | end 48 | end 49 | 50 | category do 51 | id 'Code' 52 | entry do 53 | name 'Code sample' 54 | notes <<-'END' 55 | ```ruby 56 | sample = "You can include code snippets as well" 57 | ``` 58 | Or anything else **Markdown** or HTML. 59 | END 60 | end 61 | end 62 | 63 | notes 'Some notes at the end of the cheat sheet' 64 | end 65 | ``` 66 | 67 | To convert this file to a docset, call 68 | 69 | $ cheatset generate sample.rb 70 | 71 | The following values may contain Markdown or HTML: 72 | 73 | * The `introduction` and the `notes` of the cheat sheet 74 | * The `name` and the `notes` of the entries 75 | 76 | Syntax highlighting is supported (see Ruby code in the sample). For a list of supported languages, see the [rouge](http://rouge.jneen.net/) [lexer repository](https://github.com/jneen/rouge/tree/master/spec/lexers) 77 | 78 | For more complete examples look at some of 79 | [the actual cheat sheets](https://github.com/Kapeli/cheatsheets/tree/master/cheatsheets). 80 | 81 | If you do not use Ruby or lack a working Ruby toolchain and still want to generate cheatsheets. 82 | 83 | You can use the `cheatset` Docker image. 84 | 85 | $ docker pull jonasbn/cheatset:latest 86 | $ docker run --rm -it --volume $PWD:/tmp --name cheatset jonasbn/cheatset:latest generate sample.rb 87 | 88 | For more details on the Docker image please visit the repositories on [DockerHub](https://hub.docker.com/repository/docker/jonasbn/cheatset) or [GitHub](https://github.com/jonasbn/docker-cheatset) 89 | 90 | ## Advanced Usage 91 | 92 | Apart from the attributes listed in the sample cheat sheet above, you can also use these: 93 | 94 | * `style` (under `cheatsheet`) - define any CSS style you want. See example [here](https://github.com/Kapeli/cheatsheets/blob/f9e40e30b6fde9063b7a0fb5de8fb203851b17df/cheatsheets/CSS_Named_Colors.rb#L7-L12) 95 | * `html_class` (under `category`) - define a HTML class to be added to a category. This can be used to define custom styling for each category 96 | * `td_command` (under `entry`) - just like `command`, but multiple ones are added in a separate column (as opposed to a separate row) 97 | * `td_notes` (under `entry`) - just like `notes` but can be repeated multiple times, each becoming a separate column 98 | * `html_notes` (under `entry`) - just like `notes`, but doesn't support Markdown 99 | * `index_name` (under `entry`) - this is not displayed in the cheat sheet at all. You can use it to define a separate index name (i.e what gets added to Dash's search index and is searchable in Dash). In other words, if this entry is not present, the value in `name` is used. 100 | 101 | ## Thanks 102 | 103 | [Nix-wie-weg](https://github.com/Nix-wie-weg/dasheets) for the initial code. 104 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /bin/cheatset: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | $LOAD_PATH << File.expand_path('../../lib', __FILE__) 4 | require 'cheatset' 5 | require 'cheatset/cli' 6 | Cheatset::CLI.start 7 | -------------------------------------------------------------------------------- /cheatset.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'cheatset/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'cheatset' 8 | spec.version = Cheatset::VERSION 9 | spec.authors = ['Bogdan Popescu'] 10 | spec.description = 'Generate cheat sheets for Dash' 11 | spec.summary = spec.description 12 | spec.homepage = 'https://github.com/Kapeli/cheatset' 13 | spec.license = 'MIT' 14 | 15 | spec.files = `git ls-files`.split($/) 16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 17 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 18 | spec.require_paths = ['lib'] 19 | 20 | spec.add_development_dependency 'bundler', '~> 1.3' 21 | spec.add_development_dependency 'rake' 22 | 23 | spec.add_dependency 'thor', '>= 1.0.1', '< 2.0' 24 | spec.add_dependency 'haml', '> 5.2', '< 6.0' 25 | spec.add_dependency 'sqlite3', '>= 1.3.13', '< 1.4' 26 | spec.add_dependency 'plist', '>= 3.5.0', '< 4.0' 27 | spec.add_dependency 'redcarpet', '>= 3.5.1', '< 4.0' 28 | spec.add_dependency 'rouge', '>= 3.26.0', '< 4.0' 29 | spec.add_dependency 'sanitize', '>= 5.2.1', '< 6.0' 30 | spec.add_dependency 'unindent', '>= 1.0', '< 1.1' 31 | end 32 | -------------------------------------------------------------------------------- /lib/cheatset.rb: -------------------------------------------------------------------------------- 1 | require 'cheatset/version' 2 | 3 | %w(creator dsl/base dsl/cheatsheet dsl/category dsl/context 4 | dsl/entry).each do |file| 5 | require "cheatset/#{file}" 6 | end 7 | -------------------------------------------------------------------------------- /lib/cheatset/cli.rb: -------------------------------------------------------------------------------- 1 | require 'thor' 2 | 3 | module Rouge 4 | module Formatters 5 | class HTML < Formatter 6 | def stream_untableized(tokens, &b) # prevent Rouge from using
, we just want
7 | yield "" if @wrap
8 | tokens.each{ |tok, val| span(tok, val, &b) }
9 | yield "
\n" if @wrap
10 | end
11 | end
12 | class HTMLPygments < Formatter
13 | def stream(tokens, &b) # prevent Rouge from using , we just want
14 | yield %<>
15 | @inner.stream(tokens, &b)
16 | yield "
"
17 | end
18 | end
19 | end
20 | end
21 |
22 | module Cheatset
23 | class CLI < Thor
24 | desc 'generate FILE', 'Generates cheatsheet out of a file'
25 | def generate(file)
26 | context = Cheatset::DSL::Context.new(file)
27 | context.generate
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/cheatset/creator.rb:
--------------------------------------------------------------------------------
1 | require 'plist'
2 | require 'sqlite3'
3 | require 'fileutils'
4 | require 'haml'
5 | require 'ostruct'
6 | require 'cgi'
7 | require 'pathname'
8 |
9 | class Cheatset::Creator
10 | def initialize(cheatsheet, filename)
11 | @cheatsheet = cheatsheet
12 | @filename = filename
13 | @docset_path = "#{@cheatsheet.docset_file_name}.docset"
14 | @path = "#{@docset_path}/Contents/"
15 | end
16 |
17 | def generate
18 | FileUtils.rm_rf(@path)
19 | FileUtils.mkdir_p(@path)
20 | generate_html_file
21 | generate_plist_file
22 | generate_database
23 | end
24 |
25 | private
26 |
27 | def tpl_path
28 | File.expand_path('../templates', __FILE__)
29 | end
30 |
31 | def generate_html_file
32 | # HTML
33 | template = File.read("#{tpl_path}/template.haml")
34 | engine = Haml::Engine.new(template)
35 | out = engine.render(@cheatsheet)
36 | doc_path = "#{@path}Resources/Documents/"
37 | FileUtils.mkdir_p(doc_path)
38 | File.open("#{doc_path}index.html", 'w') { |file| file.write(out) }
39 |
40 | # (static) CSS
41 | FileUtils.cp("#{tpl_path}/style.css", doc_path)
42 |
43 | # resources
44 | FileUtils.cp_r("#{tpl_path}/cheatset_resources", doc_path)
45 | resources = @cheatsheet.resources
46 | if resources && !resources.empty?
47 | if Pathname.new(resources).absolute?
48 | resources_path = resources
49 | else
50 | base_dir = File.dirname(@filename)
51 | resources_path = "#{base_dir}/#{resources}"
52 | end
53 |
54 | FileUtils.cp_r(resources_path, doc_path)
55 | end
56 | end
57 |
58 | def generate_plist_file
59 | plist_data = {
60 | 'CFBundleIdentifier' => 'cheatsheet',
61 | 'CFBundleName' => (@cheatsheet.title) ? @cheatsheet.title : 'No Title',
62 | 'DocSetPlatformFamily' => 'cheatsheet',
63 | 'DashDocSetFamily' => 'cheatsheet',
64 | 'isDashDocset' => true,
65 | 'dashIndexFilePath' => 'index.html',
66 | 'DashDocSetPluginKeyword' => (@cheatsheet.platform) ? @cheatsheet.platform : (@cheatsheet.keyword) ? @cheatsheet.keyword : 'cheatsheet',
67 | 'DashDocSetKeyword' => (@cheatsheet.keyword) ? @cheatsheet.keyword : 'cheatsheet'
68 | }
69 | File.open("#{@path}Info.plist", 'w') do |file|
70 | file.write(Plist::Emit.dump(plist_data))
71 | end
72 | end
73 |
74 | def generate_database
75 | sqlite_file = "#{@path}Resources/docSet.dsidx"
76 | db = SQLite3::Database.new(sqlite_file)
77 | db.busy_timeout = 100;
78 | db.execute <<-SQL
79 | CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT,
80 | type TEXT, path TEXT);
81 | CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path);
82 | SQL
83 |
84 | sql = 'INSERT INTO searchIndex(name, type, path) VALUES (?, ?, ?)'
85 | db.execute(sql, @cheatsheet.title, 'Category',
86 | "index.html")
87 |
88 | @cheatsheet.categories.each do |category|
89 | category_strip = CGI.escape(category.id.strip).gsub(/\//, '%252F').gsub(/\+/, '%20');
90 | if @cheatsheet.title != category.id
91 | db.execute(sql, category.id, 'Category',
92 | "index.html\#//dash_ref/Category/#{category_strip}/1")
93 | end
94 | category.entries.each_with_index do |entry, index|
95 | first_command = nil;
96 | if entry.command && entry.command.length > 0
97 | first_command = entry.command.first
98 | end
99 | href = (entry.name || entry.index_name) ? "index.html\#//dash_ref_#{category_strip}/Entry/#{CGI.escape((entry.index_name) ? entry.index_name.strip : entry.tags_stripped_name.strip).gsub(/\//, '%252F').gsub(/\+/, '%20')}/0" : (first_command) ? "index.html\#//dash_ref_#{category_strip}/Command/#{URI.escape(first_command).gsub(/\//, '%252F').gsub(/\+/, '%20')}/0" : ""
100 | if entry.command
101 | entry.command.each do |command|
102 | if(!command.strip.empty? && !entry.not_in_main_index)
103 | db.execute(sql, command.strip, 'Command', href)
104 | end
105 | end
106 | end
107 | if entry.td_command
108 | entry.td_command.each do |command|
109 | if(!command.strip.empty? && !entry.not_in_main_index)
110 | db.execute(sql, command.strip, 'Command', href)
111 | end
112 | end
113 | end
114 | if entry.name || entry.index_name
115 | if(!entry.not_in_main_index)
116 | db.execute(sql, (entry.index_name) ? entry.index_name.strip : entry.tags_stripped_name.strip, 'Entry', href)
117 | end
118 | end
119 | if entry.extra_index_name
120 | entry.extra_index_name.each do |extra_index_name|
121 | db.execute(sql, extra_index_name.strip, 'Entry', href)
122 | end
123 | end
124 | end
125 | end
126 | end
127 | end
128 |
--------------------------------------------------------------------------------
/lib/cheatset/dsl/base.rb:
--------------------------------------------------------------------------------
1 | require 'redcarpet'
2 | require 'rouge'
3 | require 'rouge/plugins/redcarpet'
4 | require 'sanitize'
5 | require 'unindent'
6 | require 'cgi'
7 |
8 | class HTML < Redcarpet::Render::HTML
9 | include Rouge::Plugins::Redcarpet
10 | end
11 |
12 | module Cheatset
13 | module DSL
14 | class Base
15 | def initialize(&block)
16 | instance_eval(&block)
17 | end
18 | private
19 |
20 | def parse_markdown(str)
21 | markdown = Redcarpet::Markdown.new(HTML, :autolink => true, :hard_wrap =>true, :disable_indented_code_blocks => true, :fenced_code_blocks => true, :tables => true)
22 | markdown.render(str)
23 | end
24 |
25 | def self.define_attrs(*names)
26 | names.each do |name|
27 | define_method(name) do |val = nil|
28 | instance_variable_set("@#{name}", val) if val
29 | instance_variable_get("@#{name}")
30 | end
31 | end
32 | end
33 | def self.define_list_attrs(*names)
34 | names.each do |name|
35 | define_method(name) do |val = nil|
36 | if val
37 | array = instance_variable_get("@#{name}")
38 | if !array
39 | instance_variable_set("@#{name}", [val])
40 | else
41 | instance_variable_set("@#{name}", array << val)
42 | end
43 | end
44 | instance_variable_get("@#{name}")
45 | end
46 | end
47 | end
48 | def self.define_markdown_list_attrs(*names)
49 | names.each do |name|
50 | define_method(name) do |val = nil|
51 | if val
52 | val = val.unindent
53 | val = parse_markdown(val)
54 | array = instance_variable_get("@#{name}")
55 | if !array
56 | instance_variable_set("@#{name}", [val])
57 | else
58 | instance_variable_set("@#{name}", array << val)
59 | end
60 | end
61 | instance_variable_get("@#{name}")
62 | end
63 | end
64 | end
65 | def self.define_markdown_attrs(*names)
66 | names.each do |name|
67 | define_method(name) do |val = nil|
68 | if val
69 | val = val.unindent
70 | val = parse_markdown(val)
71 | instance_variable_set("@#{name}", val)
72 | end
73 | instance_variable_get("@#{name}")
74 | end
75 | define_method("tags_stripped_#{name}") do
76 | CGI.unescapeHTML(Sanitize.clean(send(name).gsub("\n", ' ').squeeze(' ')))
77 | end
78 | end
79 | end
80 | end
81 | end
82 | end
83 |
--------------------------------------------------------------------------------
/lib/cheatset/dsl/category.rb:
--------------------------------------------------------------------------------
1 | module Cheatset
2 | module DSL
3 | class Category < Base
4 | attr_reader :entries
5 | define_attrs :id, :hasEntry, :html_class
6 | define_list_attrs :header
7 |
8 | def initialize(&block)
9 | @entries = []
10 | super(&block)
11 | end
12 | def entry(&block)
13 | @entries << Cheatset::DSL::Entry.new(&block)
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/cheatset/dsl/cheatsheet.rb:
--------------------------------------------------------------------------------
1 | module Cheatset
2 | module DSL
3 | class Cheatsheet < Base
4 | attr_reader :categories
5 | define_attrs :title, :docset_file_name, :keyword, :source_url, :platform, :style, :head_inject, :resources
6 | define_markdown_attrs :introduction, :notes
7 |
8 | def initialize(&block)
9 | @categories = []
10 | super(&block)
11 | end
12 |
13 | def category(&block)
14 | @categories << Cheatset::DSL::Category.new(&block)
15 | end
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/cheatset/dsl/context.rb:
--------------------------------------------------------------------------------
1 | module Cheatset
2 | module DSL
3 | class Context
4 | def initialize(filename)
5 | instance_eval(File.read(filename), File.expand_path(filename))
6 | @filename = filename
7 | end
8 | def generate
9 | Cheatset::Creator.new(@data, @filename).generate
10 | end
11 | private
12 |
13 | def cheatsheet(&block)
14 | @data = Cheatset::DSL::Cheatsheet.new(&block)
15 | end
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/cheatset/dsl/entry.rb:
--------------------------------------------------------------------------------
1 | module Cheatset
2 | module DSL
3 | class Entry < Base
4 | define_list_attrs :command, :td_command, :extra_index_name
5 | define_attrs :index_name, :not_in_main_index, :html_notes
6 | define_markdown_attrs :name, :notes
7 | define_markdown_list_attrs :td_notes
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/lib/cheatset/templates/.sass-cache/c0630dfea9543a0a71b68aca4887e98819b89684/style.scssc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/.sass-cache/c0630dfea9543a0a71b68aca4887e98819b89684/style.scssc
--------------------------------------------------------------------------------
/lib/cheatset/templates/cheatset_resources/Open_Sans.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans.woff
--------------------------------------------------------------------------------
/lib/cheatset/templates/cheatset_resources/Open_Sans_Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Bold.woff
--------------------------------------------------------------------------------
/lib/cheatset/templates/cheatset_resources/Open_Sans_Bold_Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Bold_Italic.woff
--------------------------------------------------------------------------------
/lib/cheatset/templates/cheatset_resources/Open_Sans_Extrabold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Extrabold.woff
--------------------------------------------------------------------------------
/lib/cheatset/templates/cheatset_resources/Open_Sans_Extrabold_Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Extrabold_Italic.woff
--------------------------------------------------------------------------------
/lib/cheatset/templates/cheatset_resources/Open_Sans_Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Italic.woff
--------------------------------------------------------------------------------
/lib/cheatset/templates/cheatset_resources/Open_Sans_Semibold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Semibold.woff
--------------------------------------------------------------------------------
/lib/cheatset/templates/cheatset_resources/Open_Sans_Semibold_Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Semibold_Italic.woff
--------------------------------------------------------------------------------
/lib/cheatset/templates/style.css:
--------------------------------------------------------------------------------
1 | h1, h2, h3, p, blockquote {
2 | margin: 0;
3 | padding: 0; }
4 |
5 | @font-face {
6 | font-family: 'Open Sans';
7 | font-style: normal;
8 | font-weight: 400;
9 | src: local("Open Sans"), local("OpenSans"), url(cheatset_resources/Open_Sans.woff) format("woff"); }
10 | @font-face {
11 | font-family: 'Open Sans';
12 | font-style: normal;
13 | font-weight: 600;
14 | src: local("Open Sans Semibold"), local("OpenSans-Semibold"), url(cheatset_resources/Open_Sans_Semibold.woff) format("woff"); }
15 | @font-face {
16 | font-family: 'Open Sans';
17 | font-style: normal;
18 | font-weight: 700;
19 | src: local("Open Sans Bold"), local("OpenSans-Bold"), url(cheatset_resources/Open_Sans_Bold.woff) format("woff"); }
20 | @font-face {
21 | font-family: 'Open Sans';
22 | font-style: normal;
23 | font-weight: 800;
24 | src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"), url(cheatset_resources/Open_Sans_Extrabold.woff) format("woff"); }
25 | @font-face {
26 | font-family: 'Open Sans';
27 | font-style: italic;
28 | font-weight: 400;
29 | src: local("Open Sans Italic"), local("OpenSans-Italic"), url(cheatset_resources/Open_Sans_Italic.woff) format("woff"); }
30 | @font-face {
31 | font-family: 'Open Sans';
32 | font-style: italic;
33 | font-weight: 600;
34 | src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"), url(cheatset_resources/Open_Sans_Semibold_Italic.woff) format("woff"); }
35 | @font-face {
36 | font-family: 'Open Sans';
37 | font-style: italic;
38 | font-weight: 700;
39 | src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"), url(cheatset_resources/Open_Sans_Bold_Italic.woff) format("woff"); }
40 | @font-face {
41 | font-family: 'Open Sans';
42 | font-style: italic;
43 | font-weight: 800;
44 | src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"), url(cheatset_resources/Open_Sans_Extrabold_Italic.woff) format("woff"); }
45 | body {
46 | font-family: 'Open Sans', sans-serif;
47 | font-size: 16px;
48 | color: #000;
49 | background-color: #fff;
50 | margin: 0; }
51 |
52 | code, pre {
53 | font-family: Menlo, Consolas, "Liberation Mono", Courier, monospace;
54 | font-size: 15px; }
55 |
56 | code {
57 | margin: 0;
58 | border: 1px solid #ddd;
59 | background-color: #f8f8f8;
60 | border-radius: 3px;
61 | white-space: nowrap; }
62 |
63 | .name code {
64 | vertical-align: 1px; }
65 |
66 | code:before, code:after {
67 | content: "\00a0"; }
68 |
69 | header {
70 | color: #efefef;
71 | background-color: #666;
72 | padding: 0px 10px 3px 10px; }
73 |
74 | h1 {
75 | font-size: 35px;
76 | font-weight: 600; }
77 |
78 | footer {
79 | background-color: #666;
80 | color: #efefef;
81 | text-align: center;
82 | padding: 3px 0px; }
83 | footer a {
84 | color: #efefef; }
85 |
86 | section.notes {
87 | margin-top: 1em; }
88 | section.notes h2 {
89 | color: #666;
90 | font-size: 1.5em; }
91 |
92 | article {
93 | margin: 2em 1em; }
94 |
95 | @media print {
96 | section.category {
97 | page-break-inside: avoid;
98 | break-inside: avoid;
99 | }
100 | }
101 |
102 | section.category {
103 | border: 2px solid #666;
104 | border-radius: 6px 6px;
105 | background-color: #666;
106 | margin: 2em 0;
107 | overflow: hidden;
108 | padding-bottom: 5px; }
109 | section.category h2 {
110 | color: #fff;
111 | font-size: 1.5em;
112 | text-align: center;
113 | margin-top: -2px;
114 | font-weight: 600; }
115 |
116 | table {
117 | background-color: #fff;
118 | border-collapse: collapse;
119 | width: 100%; }
120 |
121 | td {
122 | padding: 13px 8px 0px 8px;
123 | border-left: 1px solid #d7d7d7; }
124 |
125 | th {
126 | border-left: 1px solid #d7d7d7; }
127 |
128 | tr {
129 | border-bottom: 1px dotted #d7d7d7; }
130 |
131 | tr:last-child {
132 | border-bottom: none; }
133 |
134 | td.command, td.td_command {
135 | width: 1%;
136 | white-space: nowrap;
137 | vertical-align:top;
138 | padding: 9px 8px 4px 7px;
139 | text-align: right; }
140 | td.command code, td.td_command code {
141 | padding: .1em 0.2em;
142 | box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #fff inset;
143 | border-radius: 3px;
144 | border: 1px solid #ccc;
145 | background-color: #efefef;
146 | color: #333; }
147 |
148 | td.td_command {
149 | text-align: center; }
150 |
151 | td.description .name {
152 | font-size: 1.2em; }
153 |
154 | th {
155 | background: #efefef;
156 | padding: 5px 12px 5px 8px;
157 | text-align: left;
158 | border-bottom: 1px solid #d7d7d7;
159 | font-weight: 600; }
160 |
161 | th:nth-child(1), td:nth-child(1) {
162 | border-left: none; }
163 |
164 | a {
165 | color: #666; }
166 |
167 | p {
168 | margin: 0 0 7px; }
169 |
170 | .highlight {
171 | background-color: #f8f8f8;
172 | border: 1px solid #ccc;
173 | padding: 6px 10px;
174 | border-radius: 3px;
175 | margin-right: 1px;
176 | white-space: pre-wrap;
177 | word-wrap: break-word; }
178 |
179 | .c {
180 | color: #999988;
181 | font-style: italic; }
182 |
183 | .k {
184 | font-weight: bold; }
185 |
186 | .o {
187 | font-weight: bold; }
188 |
189 | .cm {
190 | color: #999988;
191 | font-style: italic; }
192 |
193 | .cp {
194 | color: #999999;
195 | font-weight: bold; }
196 |
197 | .c1 {
198 | color: #999988;
199 | font-style: italic; }
200 |
201 | .cs {
202 | color: #999999;
203 | font-weight: bold;
204 | font-style: italic; }
205 |
206 | .gd {
207 | color: #000000;
208 | background-color: #ffdddd; }
209 |
210 | .gd .x {
211 | color: #000000;
212 | background-color: #ffaaaa; }
213 |
214 | .ge {
215 | font-style: italic; }
216 |
217 | .gr {
218 | color: #aa0000; }
219 |
220 | .gh {
221 | color: #999999; }
222 |
223 | .gi {
224 | color: #000000;
225 | background-color: #ddffdd; }
226 |
227 | .gi .x {
228 | color: #000000;
229 | background-color: #aaffaa; }
230 |
231 | .go {
232 | color: #888888; }
233 |
234 | .gp {
235 | color: #555555; }
236 |
237 | .gs {
238 | font-weight: bold; }
239 |
240 | .gu {
241 | color: #800080;
242 | font-weight: bold; }
243 |
244 | .gt {
245 | color: #aa0000; }
246 |
247 | .kc {
248 | font-weight: bold; }
249 |
250 | .kd {
251 | font-weight: bold; }
252 |
253 | .kn {
254 | font-weight: bold; }
255 |
256 | .kp {
257 | font-weight: bold; }
258 |
259 | .kr {
260 | font-weight: bold; }
261 |
262 | .kt {
263 | color: #445588;
264 | font-weight: bold; }
265 |
266 | .m {
267 | color: #009999; }
268 |
269 | .s {
270 | color: #dd1144; }
271 |
272 | .n {
273 | color: #333333; }
274 |
275 | .na {
276 | color: teal; }
277 |
278 | .nb {
279 | color: #0086b3; }
280 |
281 | .nc {
282 | color: #445588;
283 | font-weight: bold; }
284 |
285 | .no {
286 | color: teal; }
287 |
288 | .ni {
289 | color: purple; }
290 |
291 | .ne {
292 | color: #990000;
293 | font-weight: bold; }
294 |
295 | .nf {
296 | color: #990000;
297 | font-weight: bold; }
298 |
299 | .nn {
300 | color: #555555; }
301 |
302 | .nt {
303 | color: navy; }
304 |
305 | .nv {
306 | color: teal; }
307 |
308 | .ow {
309 | font-weight: bold; }
310 |
311 | .w {
312 | color: #bbbbbb; }
313 |
314 | .mf {
315 | color: #009999; }
316 |
317 | .mh {
318 | color: #009999; }
319 |
320 | .mi {
321 | color: #009999; }
322 |
323 | .mo {
324 | color: #009999; }
325 |
326 | .sb {
327 | color: #dd1144; }
328 |
329 | .sc {
330 | color: #dd1144; }
331 |
332 | .sd {
333 | color: #dd1144; }
334 |
335 | .s2 {
336 | color: #dd1144; }
337 |
338 | .se {
339 | color: #dd1144; }
340 |
341 | .sh {
342 | color: #dd1144; }
343 |
344 | .si {
345 | color: #dd1144; }
346 |
347 | .sx {
348 | color: #dd1144; }
349 |
350 | .sr {
351 | color: #009926; }
352 |
353 | .s1 {
354 | color: #dd1144; }
355 |
356 | .ss {
357 | color: #990073; }
358 |
359 | .bp {
360 | color: #999999; }
361 |
362 | .vc {
363 | color: teal; }
364 |
365 | .vg {
366 | color: teal; }
367 |
368 | .vi {
369 | color: teal; }
370 |
371 | .il {
372 | color: #009999; }
373 |
374 | .gc {
375 | color: #999;
376 | background-color: #EAF2F5; }
377 |
378 | pre {
379 | padding: 15px;
380 | line-height: 17px;
381 | margin-top: 0px;
382 | margin-bottom: 9px; }
383 |
384 | .name {
385 | margin-top: -4px; }
386 |
387 | ul {
388 | padding-left: 24px; }
389 |
390 | .scrollable {
391 | overflow-x: auto; }
392 |
393 | a {
394 | -ms-word-break: break-all;
395 | -ms-word-wrap: break-all;
396 | -webkit-word-break: break-word;
397 | -webkit-word-wrap: break-word;
398 | word-break: break-word;
399 | word-wrap: break-word; }
400 |
--------------------------------------------------------------------------------
/lib/cheatset/templates/style.scss:
--------------------------------------------------------------------------------
1 | $white: #fff;
2 | $light_gray: #efefef;
3 | $dark_gray: #666;
4 | $lighter_gray: #d7d7d7;
5 | $black: #000;
6 | ////////////////////////////////////////////////////////////////////////////////
7 | h1, h2, h3, p, blockquote {
8 | margin: 0;
9 | padding: 0;
10 | }
11 | @font-face {
12 | font-family: 'Open Sans';
13 | font-style: normal;
14 | font-weight: 400;
15 | src: local('Open Sans'), local('OpenSans'), url(cheatset_resources/Open_Sans.woff) format('woff');
16 | }
17 | @font-face {
18 | font-family: 'Open Sans';
19 | font-style: normal;
20 | font-weight: 600;
21 | src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(cheatset_resources/Open_Sans_Semibold.woff) format('woff');
22 | }
23 | @font-face {
24 | font-family: 'Open Sans';
25 | font-style: normal;
26 | font-weight: 700;
27 | src: local('Open Sans Bold'), local('OpenSans-Bold'), url(cheatset_resources/Open_Sans_Bold.woff) format('woff');
28 | }
29 | @font-face {
30 | font-family: 'Open Sans';
31 | font-style: normal;
32 | font-weight: 800;
33 | src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url(cheatset_resources/Open_Sans_Extrabold.woff) format('woff');
34 | }
35 | @font-face {
36 | font-family: 'Open Sans';
37 | font-style: italic;
38 | font-weight: 400;
39 | src: local('Open Sans Italic'), local('OpenSans-Italic'), url(cheatset_resources/Open_Sans_Italic.woff) format('woff');
40 | }
41 | @font-face {
42 | font-family: 'Open Sans';
43 | font-style: italic;
44 | font-weight: 600;
45 | src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url(cheatset_resources/Open_Sans_Semibold_Italic.woff) format('woff');
46 | }
47 | @font-face {
48 | font-family: 'Open Sans';
49 | font-style: italic;
50 | font-weight: 700;
51 | src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(cheatset_resources/Open_Sans_Bold_Italic.woff) format('woff');
52 | }
53 | @font-face {
54 | font-family: 'Open Sans';
55 | font-style: italic;
56 | font-weight: 800;
57 | src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url(cheatset_resources/Open_Sans_Extrabold_Italic.woff) format('woff');
58 | }
59 |
60 | body {
61 | font-family: 'Open Sans', sans-serif;
62 | font-size: 14px;
63 | color: $black;
64 | background-color: $white;
65 | margin: 0;
66 | }
67 | code, pre {
68 | font-family: Menlo, Consolas, "Liberation Mono", Courier, monospace;
69 | font-size:13px;
70 | }
71 |
72 | code {
73 | margin:0;
74 | border:1px solid #ddd;
75 | background-color:#f8f8f8;
76 | border-radius:3px;
77 | white-space:nowrap;
78 | }
79 |
80 | .name code {
81 | vertical-align:1px;
82 | }
83 |
84 | code:before, code:after {
85 | content: "\00a0";
86 | }
87 |
88 | ////////////////////////////////////////////////////////////////////////////////
89 | header {
90 | color: $light_gray;
91 | background-color: $dark_gray;
92 | padding: 0px 10px 3px 10px;
93 | }
94 | h1 {
95 | font-size: 35px;
96 | font-weight:600;
97 | }
98 |
99 | ////////////////////////////////////////////////////////////////////////////////
100 | footer {
101 | background-color: $dark_gray;
102 | color: $light_gray;
103 | text-align: center;
104 | padding:3px 0px;
105 | a {
106 | color: $light_gray;
107 | }
108 | }
109 | ////////////////////////////////////////////////////////////////////////////////
110 | // notes
111 | section.notes {
112 | margin-top: 1em;
113 | h2 {
114 | color: $dark_gray;
115 | font-size: 1.5em;
116 | }
117 | }
118 | ////////////////////////////////////////////////////////////////////////////////
119 | article {
120 | margin: 2em 1em;
121 | }
122 |
123 | @media print {
124 | section.category {
125 | page-break-inside: avoid;
126 | break-inside: avoid;
127 | }
128 | }
129 |
130 | section.category {
131 | border: 2px solid $dark_gray;
132 | border-radius: 6px 6px;
133 | background-color: $dark_gray;
134 | margin: 2em 0;
135 | overflow: hidden;
136 | h2 {
137 | color: $white;
138 | font-size: 1.5em;
139 | text-align: center;
140 | margin-top: -2px;
141 | font-weight:600;
142 | }
143 | padding-bottom: 5px;
144 | }
145 | table {
146 | background-color: $white;
147 | border-collapse: collapse;
148 | width: 100%;
149 | }
150 | td {
151 | padding: 13px 8px 0px 8px;
152 | border-left:1px solid $lighter_gray;
153 | }
154 | th {
155 | border-left:1px solid $lighter_gray;
156 | }
157 | tr {
158 | border-bottom:1px dotted $lighter_gray;
159 | }
160 | tr:last-child {
161 | border-bottom:none;
162 | }
163 | td.command {
164 | width: 1%;
165 | white-space: nowrap;
166 | vertical-align:top;
167 | padding: 9px 8px 4px 7px;
168 | text-align:right;
169 | // border-right:1px solid $lighter_gray;
170 | code {
171 | // Nice key styling:
172 | // https://developers.google.com/chrome-developer-tools/docs/shortcuts
173 | padding: .1em 0.2em;
174 | box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #fff inset;
175 | border-radius: 3px;
176 | border: 1px solid #ccc;
177 | background-color: $light_gray;
178 | color: #333;
179 | }
180 | }
181 |
182 | td.td_command {
183 | @extend td.command;
184 | text-align:center;
185 | }
186 |
187 | td.description {
188 | .name {
189 | font-size: 1.2em;
190 | }
191 | }
192 |
193 | th {
194 | background: $light_gray;
195 | padding:5px 12px 5px 8px;
196 | text-align: left;
197 | border-bottom: 1px solid $lighter_gray;
198 | font-weight:600;
199 | }
200 |
201 | th:nth-child(1), td:nth-child(1) {
202 | border-left:none;
203 | }
204 |
205 | a {
206 | color: $dark_gray;
207 | }
208 |
209 | p {
210 | margin:0 0 7px;
211 | }
212 |
213 | .highlight { background-color: #f8f8f8; border: 1px solid #ccc; padding: 6px 10px; border-radius: 3px; margin-right:1px; white-space: pre-wrap; word-wrap:break-word;}
214 | .c { color: #999988; font-style: italic; }
215 | .k { font-weight: bold; }
216 | .o { font-weight: bold; }
217 | .cm { color: #999988; font-style: italic; }
218 | .cp { color: #999999; font-weight: bold; }
219 | .c1 { color: #999988; font-style: italic; }
220 | .cs { color: #999999; font-weight: bold; font-style: italic; }
221 | .gd { color: #000000; background-color: #ffdddd; }
222 | .gd .x { color: #000000; background-color: #ffaaaa; }
223 | .ge { font-style: italic; }
224 | .gr { color: #aa0000; }
225 | .gh { color: #999999; }
226 | .gi { color: #000000; background-color: #ddffdd; }
227 | .gi .x { color: #000000; background-color: #aaffaa; }
228 | .go { color: #888888; }
229 | .gp { color: #555555; }
230 | .gs { font-weight: bold; }
231 | .gu { color: #800080; font-weight: bold; }
232 | .gt { color: #aa0000; }
233 | .kc { font-weight: bold; }
234 | .kd { font-weight: bold; }
235 | .kn { font-weight: bold; }
236 | .kp { font-weight: bold; }
237 | .kr { font-weight: bold; }
238 | .kt { color: #445588; font-weight: bold; }
239 | .m { color: #009999; }
240 | .s { color: #dd1144; }
241 | .n { color: #333333; }
242 | .na { color: teal; }
243 | .nb { color: #0086b3; }
244 | .nc { color: #445588; font-weight: bold; }
245 | .no { color: teal; }
246 | .ni { color: purple; }
247 | .ne { color: #990000; font-weight: bold; }
248 | .nf { color: #990000; font-weight: bold; }
249 | .nn { color: #555555; }
250 | .nt { color: navy; }
251 | .nv { color: teal; }
252 | .ow { font-weight: bold; }
253 | .w { color: #bbbbbb; }
254 | .mf { color: #009999; }
255 | .mh { color: #009999; }
256 | .mi { color: #009999; }
257 | .mo { color: #009999; }
258 | .sb { color: #dd1144; }
259 | .sc { color: #dd1144; }
260 | .sd { color: #dd1144; }
261 | .s2 { color: #dd1144; }
262 | .se { color: #dd1144; }
263 | .sh { color: #dd1144; }
264 | .si { color: #dd1144; }
265 | .sx { color: #dd1144; }
266 | .sr { color: #009926; }
267 | .s1 { color: #dd1144; }
268 | .ss { color: #990073; }
269 | .bp { color: #999999; }
270 | .vc { color: teal; }
271 | .vg { color: teal; }
272 | .vi { color: teal; }
273 | .il { color: #009999; }
274 | .gc { color: #999; background-color: #EAF2F5; }
275 |
276 | pre {
277 | padding: 15px;
278 | line-height: 17px;
279 | margin-top: 0px;
280 | margin-bottom: 9px;
281 | }
282 |
283 | .name {
284 | margin-top: -4px;
285 | }
286 |
287 | ul {
288 | padding-left: 24px;
289 | }
290 |
291 | .scrollable {
292 | overflow-x:auto;
293 | }
294 |
295 | a {
296 | -ms-word-break: break-all;
297 | -ms-word-wrap: break-all;
298 | -webkit-word-break: break-word;
299 | -webkit-word-wrap: break-word;
300 | word-break: break-word;
301 | word-wrap: break-word;
302 | }
--------------------------------------------------------------------------------
/lib/cheatset/templates/template.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %meta{charset: 'utf-8'}
5 | %title= title
6 | %link{rel: 'stylesheet', href: 'style.css'}
7 | - if style
8 | %style{type: 'text/css'}= style
9 | - if head_inject
10 | = head_inject
11 | - categories.each do |category|
12 | %link{href: "//dash_ref/Category/#{category.id.strip.gsub(/\//, '%2F')}/1"}
13 | - category.hasEntry(false)
14 | - category.entries.each_with_index do |entry, index|
15 | - if entry.name || entry.index_name
16 | - category.hasEntry(true)
17 | %link{href: "//dash_ref_#{category.id.strip.gsub(/\//, '%2F')}/Entry/#{(entry.name) ? entry.tags_stripped_name.strip.gsub(/\//, '%2F') : entry.index_name.strip.gsub(/\//, '%2F')}/0"}
18 | - elsif entry.command && entry.command.length > 0
19 | - category.hasEntry(true)
20 | %link{href: "//dash_ref_#{category.id.strip.gsub(/\//, '%2F')}/Command/#{entry.command.first.strip.gsub(/\//, '%2F')}/0"}
21 | - if !category.hasEntry
22 | %link{href: "//dash_ref/Entry/#{category.id.strip.gsub(/\//, '%2F')}/0"}
23 |
24 | %body
25 | %header
26 | %h1= title
27 |
28 | %article
29 | %p~ introduction
30 |
31 | - categories.each do |category|
32 | %section.category{class: category.html_class}
33 | - if !category.hasEntry
34 | %a{name: "//dash_ref/Entry/#{category.id.strip.gsub(/\//, '%2F')}/0"}
35 | %h2{id:"//dash_ref/Category/#{category.id.strip.gsub(/\//, '%2F')}/1"}
36 | = category.id
37 | %div.scrollable
38 | %table
39 | - if category.header
40 | %tr
41 | - category.header.each do |header|
42 | %th~ header
43 |
44 | - category.entries.each_with_index do |entry, index|
45 | %tr{id: ((entry.name || entry.index_name) ? "//dash_ref_#{category.id.strip.gsub(/\//, '%2F')}/Entry/#{(entry.name) ? entry.tags_stripped_name.strip.gsub(/\//, '%2F') : entry.index_name.strip.gsub(/\//, '%2F')}/0" : "//dash_ref_#{category.id.strip.gsub(/\//, '%2F')}/Command/#{entry.command.first.strip.gsub(/\//, '%2F')}/0" if (entry.name || entry.index_name || (entry.command && entry.command.length > 0)) )}
46 | - if entry.command
47 | %td.command
48 | - entry.command.each do |command|
49 | %p
50 | %code= CGI.escapeHTML(command)
51 | - if entry.td_command
52 | - entry.td_command.each do |command|
53 | %td.td_command
54 | - if !command.empty?
55 | %code= CGI.escapeHTML(command)
56 | - if entry.name || entry.notes || entry.html_notes
57 | %td.description{:colspan => ("2" unless entry.command || entry.td_command || entry.td_notes)}
58 | .name~ entry.name
59 | .notes~ entry.notes
60 | .notes~ entry.html_notes
61 | - if entry.td_notes
62 | - entry.td_notes.each do |notes|
63 | %td.td_notes
64 | - if !notes.empty?
65 | .td_notes~ notes
66 | - if notes
67 | %section.notes
68 | %h2 Notes
69 | ~ notes
70 | %footer
71 | - if source_url
72 | You can modify and improve this cheat sheet here
73 | - else
74 | Generated with cheatset
--------------------------------------------------------------------------------
/lib/cheatset/version.rb:
--------------------------------------------------------------------------------
1 | module Cheatset
2 | VERSION = '1.4.8'
3 | end
4 |
--------------------------------------------------------------------------------