cheatr 0.0.1

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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cheatr.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ernesto Garcia
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.
@@ -0,0 +1,173 @@
1
+ # cheatr
2
+
3
+ Cheatr is a simple command line utility to access cheat sheets from an online
4
+ repository.
5
+
6
+ Generally speaking, cheatr is a tool that allows to host an online collection
7
+ of cheat sheets, and lets users query and maintain this repository remotely via
8
+ a command line client utility.
9
+
10
+ ### What is a cheat sheet?
11
+
12
+ In the context of cheatr, a cheat sheet is a small document with quick tips and
13
+ hints on a concrete and specific topic. Typically it contains notes intended
14
+ to aid one's memory, like listing common and useful shortcuts used on
15
+ a program, quick and easy tips on how to use a library, or the command line
16
+ options of a shell command, for instance.
17
+
18
+ Cheatr however enforces very little on the contents of the cheat sheets in
19
+ a repository. The above specification is just a guideline on the intended use
20
+ of this tool, but in practice you can use it to store and maintain any
21
+ collection of text documents in it.
22
+
23
+ Further down this document you'll find more information about the format of
24
+ [cheat sheet contents](#cheat-sheet-contents).
25
+
26
+ ## Installation
27
+
28
+ $ gem install cheatr
29
+
30
+ ## Usage
31
+
32
+ Cheatr retrieves cheat sheets from a remote server, so we need to tell
33
+ cheatr where to look.
34
+
35
+ $ cheatr config server cheatr.gnapse.com
36
+
37
+ This generates a configuration file in `~/.cheatr/config.yml`. Now we can
38
+ start querying the remote server for cheat sheets, or start creating new ones.
39
+
40
+ $ cheatr show "ruby*" # Cheat sheets with names starting with 'ruby'
41
+ ruby.strings
42
+ ruby.blocks
43
+ rubygems
44
+
45
+ $ cheatr search ruby # With this command you can ommit the wildcard
46
+ ruby.strings
47
+ ruby.blocks
48
+ rubygems
49
+
50
+ $ cheatr all # Lists all cheat sheets available
51
+ ack
52
+ bash
53
+ cplusplus
54
+ ...
55
+ ruby
56
+ vim
57
+ zsh
58
+
59
+ Tell cheatr to show a given cheat sheet.
60
+
61
+ $ cheatr show ruby.blocks
62
+ Ruby blocks are an awesome language feature!
63
+
64
+ The contents of a cheat sheet are cached once it has been fetched. You can
65
+ force cheatr to fetch remote contents.
66
+
67
+ $ cheatr show ruby.blocks -r
68
+
69
+ You can edit existing cheat sheets, or create new ones.
70
+
71
+ $ cheatr edit ruby.blocks
72
+
73
+ This will launch you preferred `$EDITOR` with the current contents of the
74
+ specified cheat sheet. After you save the file and quit the editor, `cheatr`
75
+ will update the cheat sheet contents.
76
+
77
+ Cheatr commands provide help, so you can discover all its features and
78
+ possibilities. Type `cheatr --help` or `cheatr <command> --help` for details.
79
+
80
+ ## Web server
81
+
82
+ This gem includes the server side component as well, so anyone can host their
83
+ own cheat sheets service. This server offers the basic API-like calls to
84
+ query, retrieve and modify cheat sheet contents. You can start a cheatr
85
+ server with the following command:
86
+
87
+ $ cheatr server /path/to/cheatr/repository
88
+
89
+ The repository path refers to the location where the cheats repository can be
90
+ found. A cheatr repository is nothing more than a git repository holding the
91
+ cheat sheets as files in it. If omitted, the current working directory is
92
+ assummed.
93
+
94
+ A cheatr server is a [sinatra][] app, so it can also be started using [rack][].
95
+ Every cheatr repository, when created, is initialized with a standard
96
+ `config.ru` file. So while placed in the repository's root folder, the server
97
+ can be started with the following command:
98
+
99
+ $ rackup
100
+
101
+ Also try `rackup --help` for more options.
102
+
103
+ [sinatra]: http://www.sinatrarb.com
104
+ [rack]: https://github.com/rack/rack
105
+
106
+ ### Web interface
107
+
108
+ Additionally, cheatr servers can be accessed directly on a browser, where
109
+ content is delivered as traditional hyperlinked web pages instead of mere plain
110
+ text, with the possibility to search for cheat sheets, or [link between
111
+ them](#cheat-sheet-hyperlinks), converting cheatr in a simple but powerful
112
+ cheat sheets wiki.
113
+
114
+ To try this, type the following command:
115
+
116
+ $ cheatr browse ruby.blocks
117
+
118
+ It will open the contents of the specified cheat sheet in your preferred
119
+ browser. Or you can always type the URLs in your browser yourself, provided
120
+ you know the cheatr server you want to access.
121
+
122
+ ## Cheat sheet contents
123
+
124
+ Although cheatr does not enforce any format to the contents of cheat sheets,
125
+ it assumes they consist of markdown text. Thus is highly beneficial to adhere
126
+ to this convention, and embrace it.
127
+
128
+ ### Cheat sheet hyperlinks
129
+
130
+ In addition to standard markdown syntax, cheatr supports a minor custom
131
+ extension, that becomes useful when browsing a cheatr server in a web
132
+ browser. This is related to linking in between cheat sheets, as hinted in the
133
+ previous section.
134
+
135
+ This is best shown with an example.
136
+
137
+ ```
138
+ Dynamic languages, like {{ruby}} and {{python}}, are more versatile than
139
+ {{c++|cplusplus}} in many situations.
140
+ ```
141
+
142
+ Noticed the slices of text surrounded by doble braces? These are cheatr
143
+ hyperlinks. When showing pages through the web interface in a browser, these
144
+ will be converted to links to the appropriate cheat sheet.
145
+
146
+ Note also the link to the `cplusplus` cheat sheet. The text before the
147
+ vertical bar will be used as the link text, whereas the text after it is the
148
+ name of the cheat sheet to link to.
149
+
150
+ In the command line, these "links" will be shown unmodified, still serving the
151
+ purpose of discovery, because the user can identify these "links" and discover
152
+ new related topics to continue "browsing" and learning.
153
+
154
+ ## Contributing
155
+
156
+ Feel free to dive into the code to understand more about how cheatr works, or
157
+ just for fun. Please note that this is a very young project with very rough
158
+ edges still. Issues reports and pull requests are welcome!
159
+
160
+ In case you decide to step in:
161
+
162
+ 1. Fork the repo (`git clone https://github.com/gnapse/cheatr.git`)
163
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
164
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
165
+ 4. Push to the branch (`git push origin my-new-feature`)
166
+ 5. Create new Pull Request
167
+
168
+ ## Thanks
169
+
170
+ Thanks to [defunkt][] for [cheat][], which provided the idea for this project.
171
+
172
+ [defunkt]: https://github.com/defunkt
173
+ [cheat]: https://github.com/defunkt/cheat
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "slop"
4
+ require "cheatr"
5
+
6
+ def check(condition, message)
7
+ unless condition
8
+ $stderr.puts message
9
+ exit
10
+ end
11
+ end
12
+
13
+ unless ARGV.first == 'config'
14
+ check Cheatr::Client.server, "Run 'cheatr config server <location>' to set the remote cheatr server."
15
+ end
16
+
17
+ Slop.parse help: true do
18
+
19
+ command :server do
20
+ banner 'Usage: cheatr server [options] [repository-path]'
21
+ on 'p', 'port=', 'The port where the server will listen to.'
22
+ run do |opts, args|
23
+ check args.length <= 1, opts
24
+ repository = args.first || Dir.pwd
25
+ Cheatr::Server.run(repository, opts)
26
+ end
27
+ end
28
+
29
+ command :show do
30
+ banner 'Usage: cheatr show [options] <sheet-name>'
31
+ on 'r', 'remote', 'Forces retrieving contents from remote, ignoring the cache, if any.'
32
+ run do |opts, args|
33
+ check args.length == 1, opts
34
+ name = args.first
35
+ if name.include?('*')
36
+ Cheatr::Client.search_sheets(name)
37
+ else
38
+ Cheatr::Client.display_sheet(name, ignore_cache: opts[:remote])
39
+ end
40
+ end
41
+ end
42
+
43
+ command :browse do
44
+ banner 'Usage: cheatr browse [query]'
45
+ run do |opts, args|
46
+ check args.length <= 1, opts
47
+ Cheatr::Client.browse(args.first)
48
+ end
49
+ end
50
+
51
+ command :search do
52
+ banner 'Usage: cheatr search <query>'
53
+ run do |opts, args|
54
+ check args.length == 1, opts
55
+ Cheatr::Client.search_sheets(args.first)
56
+ end
57
+ end
58
+
59
+ command :all do
60
+ banner 'Usage: cheatr all'
61
+ run do |opts, args|
62
+ check args.length == 0, opts
63
+ Cheatr::Client.search_sheets
64
+ end
65
+ end
66
+
67
+ command :edit do
68
+ banner 'Usage: cheatr edit [options] <sheet-name>'
69
+ on 'y', 'yes', 'Do not ask for confirmation after editing.'
70
+ run do |opts, args|
71
+ check args.length == 1, opts
72
+ Cheatr::Client.edit_sheet(args.first, skip_confirmation: opts[:yes])
73
+ end
74
+ end
75
+
76
+ command :fetch do
77
+ banner 'Usage: cheatr fetch [options] <sheet-name>+'
78
+ on 'q', 'quiet', 'Do not print anything to standard output. Overrides --errors.'
79
+ on 'e', 'errors', 'Print error messages only.'
80
+ run do |opts, args|
81
+ Cheatr::Client.fetch_sheets(args, opts)
82
+ end
83
+ end
84
+
85
+ command :clear do
86
+ banner 'Usage: cheatr clear [options] [sheet-name]'
87
+ on 'a', 'all', 'Clear all cached cheat sheets. Requires confirmation by default.'
88
+ on 'y', 'yes', 'Do not ask for confirmation for clearing the cache completely.'
89
+ on 'q', 'quiet', 'Do not print anything to standard output. Implies --yes, skipping confirmation.'
90
+ run do |opts, args|
91
+ if opts[:all]
92
+ Cheatr::Client.clear_cache(:all, skip_confirmation: opts[:yes], quiet: opts[:quiet])
93
+ else
94
+ check(args.length == 1, opts)
95
+ Cheatr::Client.clear_cache(args.first, quiet: opts[:quiet])
96
+ end
97
+ end
98
+ end
99
+
100
+ command :config do
101
+ banner 'Usage: cheatr config <param> <value>'
102
+ run do |opts, args|
103
+ check args.length == 2, opts
104
+ Cheatr::Client.set_config(args.first => args.last)
105
+ end
106
+ end
107
+
108
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cheatr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cheatr"
8
+ spec.version = Cheatr::VERSION
9
+ spec.authors = ["Ernesto García"]
10
+ spec.email = ["gnapse@gmail.com"]
11
+ spec.description = %q{Display cheat sheets for a variety of programs, tools and libraries, right on the command line.}
12
+ spec.summary = %q{Display cheat sheets right on the command line.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "slop"
22
+
23
+ # server dependencies
24
+ spec.add_dependency "git"
25
+ spec.add_dependency "sinatra"
26
+ spec.add_dependency "activemodel"
27
+ spec.add_dependency "redcarpet"
28
+
29
+ # client dependencies
30
+ spec.add_dependency "rest-client"
31
+ spec.add_dependency "pager"
32
+
33
+ # test dependencies
34
+ spec.add_development_dependency "bundler", "~> 1.3"
35
+ spec.add_development_dependency "rake"
36
+ spec.add_development_dependency "rspec"
37
+ end
@@ -0,0 +1,6 @@
1
+ module Cheatr
2
+ autoload :Client, 'cheatr/client'
3
+ autoload :Server, 'cheatr/server'
4
+
5
+ SHEET_NAME_REGEXP = /\A[a-z]+([\.\-\_][a-z]+)*\z/
6
+ end
@@ -0,0 +1,133 @@
1
+ require "yaml"
2
+ require "pager"
3
+ require "cheatr/client/sheet"
4
+
5
+ module Cheatr
6
+ module Client
7
+ extend Pager
8
+
9
+ # Actions
10
+
11
+ def self.search_sheets(query = nil)
12
+ query += '*' unless query.nil? || query.include?('*')
13
+ page
14
+ puts Sheet.all(query)
15
+ end
16
+
17
+ def self.display_sheet(name, opts = {})
18
+ sheet = Sheet.new(name, opts)
19
+ if sheet.contents
20
+ page
21
+ puts "(cached version)" unless sheet.remote?
22
+ puts sheet.contents
23
+ else
24
+ puts sheet.errors.first
25
+ end
26
+ end
27
+
28
+ def self.edit_sheet(name, opts = {})
29
+ sheet = Sheet.new(name, ignore_cache: true)
30
+
31
+ file = Tempfile.new([name, '.md'])
32
+ file.write(sheet.contents) if sheet.contents
33
+ file.close
34
+ system "#{editor} #{file.path}"
35
+ file.open
36
+ contents = file.read
37
+ file.close
38
+
39
+ if contents.strip.empty?
40
+ puts "Edited sheet contents were empty so nothing was saved."
41
+ return
42
+ end
43
+
44
+ if opts[:skip_confirmation] || confirm("Do you want to update the '#{name}' cheat sheet?")
45
+ sheet.contents = contents
46
+ if sheet.save
47
+ puts "Sheet '#{name}' was updated successfully."
48
+ else
49
+ puts "Sheet '#{name}' could not be updated."
50
+ $stderr.puts "Error: #{sheet.errors.first}" if sheet.errors
51
+ end
52
+ else
53
+ puts "Sheet '#{name}' was left unchanged."
54
+ end
55
+ end
56
+
57
+ def self.browse(query = nil)
58
+ open_cmd = `uname` =~ /Darwin/ ? 'open' : 'xdg-open'
59
+ uri = "http://#{server}/#{query}"
60
+ exec "#{open_cmd} #{uri}"
61
+ end
62
+
63
+ def self.fetch_sheets(arr, opts = {})
64
+ arr.each do |name|
65
+ sheet = Sheet.new(name, ignore_cache: true)
66
+ if sheet.contents
67
+ puts "Sheet '#{name}' fetched successfully." unless opts[:quiet] || opts[:errors]
68
+ else
69
+ message = sheet.errors.first || "Sheet '#{name}' could not be fetched."
70
+ puts message unless opts[:quiet]
71
+ end
72
+ end
73
+ end
74
+
75
+ def self.clear_cache(name = :all, opts = {})
76
+ if name == :all
77
+ if opts[:quiet] || opts[:skip_confirmation] || confirm("Are you sure you want clear all cheat sheets cache?")
78
+ FileUtils.rm Dir.glob("#{cache_dir}/*.md")
79
+ puts "All cached cheat sheets have been removed." unless opts[:quiet]
80
+ else
81
+ puts "Cached cheat sheets were not removed." unless opts[:quiet]
82
+ end
83
+ else
84
+ FileUtils.rm "#{cache_dir}/#{name}.md", force: true
85
+ puts "Removed cached version of '#{name}'." unless opts[:quiet]
86
+ end
87
+ end
88
+
89
+ # Configuration settings
90
+
91
+ def self.mkdir(dir)
92
+ FileUtils.mkdir_p dir
93
+ dir
94
+ end
95
+
96
+ def self.cheatr_dir
97
+ @@cheatr_dir ||= mkdir File.join(File.expand_path("~"), ".cheatr")
98
+ end
99
+
100
+ def self.cache_dir
101
+ @@cache_dir ||= mkdir File.join(cheatr_dir, 'cache', server.gsub(/:\d+\z/, ''))
102
+ end
103
+
104
+ def self.server
105
+ @@sever ||= config['server']
106
+ end
107
+
108
+ def self.editor
109
+ @@editor ||= ENV['EDITOR']
110
+ end
111
+
112
+ def self.config_file
113
+ @@config_file ||= File.join(cheatr_dir, 'config.yml')
114
+ end
115
+
116
+ def self.config
117
+ @@config ||= YAML.load_file(config_file) || {} rescue {}
118
+ end
119
+
120
+ def self.set_config(options)
121
+ config.merge!(options)
122
+ File.open(config_file, 'w') { |f| f.write config.to_yaml }
123
+ end
124
+
125
+ private
126
+
127
+ def self.confirm(message)
128
+ print "#{message} (yes/no) "
129
+ answer = $stdin.gets.chomp
130
+ %w(yes Yes YES y Y).include? answer
131
+ end
132
+ end
133
+ end