misfortune 0.1.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.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/README.md +2 -0
- data/bin/misfortune +6 -0
- data/bin/setup +8 -0
- data/data/source.md +1363 -0
- data/lib/misfortune.rb +7 -0
- data/lib/misfortune/cli/binge_command.rb +46 -0
- data/lib/misfortune/cli/random_command.rb +18 -0
- data/lib/misfortune/cli/runner.rb +33 -0
- data/lib/misfortune/cookie_jar.rb +27 -0
- data/lib/misfortune/flavor.rb +28 -0
- data/lib/misfortune/render/terminal.rb +135 -0
- data/lib/misfortune/version.rb +3 -0
- data/misfortune.gemspec +38 -0
- metadata +156 -0
data/lib/misfortune.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Misfortune
|
2
|
+
module CLI
|
3
|
+
class BingeCommand
|
4
|
+
attr_reader :options, :cookies, :flavor
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
@cookies = CookieJar.new(options['source']).cookies
|
9
|
+
@flavor = Flavor.new(:terminal)
|
10
|
+
|
11
|
+
trap_interrupt
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
current = 0
|
16
|
+
loop do
|
17
|
+
render(cookies[current % cookies_count])
|
18
|
+
current = select_cookie(current)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def cookies_count
|
25
|
+
@cookies_count ||= cookies.count
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(cookie)
|
29
|
+
system 'clear'
|
30
|
+
puts flavor.apply_to(cookie)
|
31
|
+
puts "\n\nPress ENTER to continue\n\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
def select_cookie(current)
|
35
|
+
selection = STDIN.gets.chomp.to_i
|
36
|
+
selection > 0 ? selection : current + 1
|
37
|
+
end
|
38
|
+
|
39
|
+
def trap_interrupt
|
40
|
+
Signal.trap('INT') do
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Misfortune
|
2
|
+
module CLI
|
3
|
+
class RandomCommand
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
cookie = CookieJar.new(options['source']).cookies.sample
|
12
|
+
flavor = Flavor.new(options[:flavor])
|
13
|
+
|
14
|
+
puts flavor.apply_to(cookie)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'misfortune/cli/random_command'
|
3
|
+
require 'misfortune/cli/binge_command'
|
4
|
+
|
5
|
+
module Misfortune
|
6
|
+
module CLI
|
7
|
+
class Runner < Thor
|
8
|
+
def self.flavors
|
9
|
+
Misfortune::Flavor::FLAVORS_MAP.keys.join(', ')
|
10
|
+
end
|
11
|
+
|
12
|
+
default_task :random
|
13
|
+
|
14
|
+
class_option :source, type: :string, desc: 'Source markdown file'
|
15
|
+
|
16
|
+
desc 'random', 'Prints a random cookie.'
|
17
|
+
method_option :flavor,
|
18
|
+
type: :string,
|
19
|
+
default: :terminal,
|
20
|
+
desc: "Select output flavor. Available options: #{flavors}"
|
21
|
+
|
22
|
+
def random
|
23
|
+
RandomCommand.new(options).run
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'binge', 'Non-stop cookies'
|
27
|
+
|
28
|
+
def binge
|
29
|
+
BingeCommand.new(options).run
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Misfortune
|
2
|
+
class CookieJar
|
3
|
+
attr_reader :file
|
4
|
+
|
5
|
+
def initialize(file = nil)
|
6
|
+
@file = file || data_file_path('source')
|
7
|
+
end
|
8
|
+
|
9
|
+
def cookies
|
10
|
+
@cookies ||= file_chunks
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def file_chunks
|
16
|
+
File.read(file)
|
17
|
+
.split(/\n#\s/)
|
18
|
+
.map(&:strip)
|
19
|
+
.reject(&:empty?)
|
20
|
+
.map { |chunk| chunk.prepend '#' }
|
21
|
+
end
|
22
|
+
|
23
|
+
def data_file_path(name)
|
24
|
+
File.join(File.dirname(__FILE__), '..', '..', 'data', "#{name}.md")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Misfortune
|
2
|
+
class Flavor
|
3
|
+
FLAVORS_MAP = {
|
4
|
+
html: Redcarpet::Render::HTML,
|
5
|
+
vanilla: Redcarpet::Render::StripDown,
|
6
|
+
terminal: Misfortune::Render::Terminal
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
REDCARPET_OPTIONS = {
|
10
|
+
fenced_code_blocks: true,
|
11
|
+
strikethrough: true,
|
12
|
+
autolink: true
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
attr_reader :markdown
|
16
|
+
|
17
|
+
def initialize(kind)
|
18
|
+
@markdown = Redcarpet::Markdown.new(
|
19
|
+
FLAVORS_MAP.fetch(kind.to_sym),
|
20
|
+
REDCARPET_OPTIONS
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def apply_to(cookie)
|
25
|
+
markdown.render(cookie).chomp
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'pastel'
|
2
|
+
|
3
|
+
module Misfortune
|
4
|
+
module Render
|
5
|
+
class Terminal < Redcarpet::Render::StripDown
|
6
|
+
BLOCK_MAX_WITH = 80
|
7
|
+
BLOCK_DELIMITER = '~'.freeze
|
8
|
+
LIST_INDENTATION = ' '.freeze
|
9
|
+
LIST_ORDERED_ITEM_PREFIX = '<ENUM>'.freeze
|
10
|
+
LIST_ORDERED_ITEM_CHAR = '.'.freeze
|
11
|
+
LIST_UNORDERED_ITEM_CHAR = '-'.freeze
|
12
|
+
|
13
|
+
attr_reader :pastel
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@pastel = Pastel.new(enabled: $stdout.tty?, eachline: new_line)
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def header(text, _header_level)
|
22
|
+
text = pastel.underline(text)
|
23
|
+
surround_with_line_breaks(text, 0, 2)
|
24
|
+
end
|
25
|
+
|
26
|
+
def block_code(code, language)
|
27
|
+
text = ''
|
28
|
+
text << labeled_hrule(language)
|
29
|
+
text << indent(code(code))
|
30
|
+
text << hrule
|
31
|
+
|
32
|
+
surround_with_line_breaks(text, 1, 2)
|
33
|
+
end
|
34
|
+
|
35
|
+
def block_quote(quote)
|
36
|
+
text = pastel.cyan(quote)
|
37
|
+
surround_with_line_breaks(text, 1, 2)
|
38
|
+
end
|
39
|
+
|
40
|
+
def paragraph(text)
|
41
|
+
surround_with_line_breaks(text, 0, 2)
|
42
|
+
end
|
43
|
+
|
44
|
+
def list(contents, list_type)
|
45
|
+
contents = enumerate_list(contents) if list_type == :ordered
|
46
|
+
contents = indent(contents)
|
47
|
+
|
48
|
+
surround_with_line_breaks(contents, 0, 1)
|
49
|
+
end
|
50
|
+
|
51
|
+
def list_item(text, list_type)
|
52
|
+
prefix =
|
53
|
+
case list_type
|
54
|
+
when :ordered
|
55
|
+
LIST_ORDERED_ITEM_PREFIX
|
56
|
+
when :unordered
|
57
|
+
LIST_UNORDERED_ITEM_CHAR
|
58
|
+
end
|
59
|
+
|
60
|
+
"#{prefix} #{text}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def hrule
|
64
|
+
labeled_hrule('')
|
65
|
+
end
|
66
|
+
|
67
|
+
def emphasis(text)
|
68
|
+
pastel.underline(text)
|
69
|
+
end
|
70
|
+
|
71
|
+
def double_emphasis(text)
|
72
|
+
pastel.bold(text)
|
73
|
+
end
|
74
|
+
|
75
|
+
def triple_emphasis(text)
|
76
|
+
emphasis(double_emphasis(text))
|
77
|
+
end
|
78
|
+
|
79
|
+
def strikethrough(text)
|
80
|
+
pastel.strikethrough(text)
|
81
|
+
end
|
82
|
+
|
83
|
+
def link(link, _title, content)
|
84
|
+
"#{content} (#{pastel.blue(link)})"
|
85
|
+
end
|
86
|
+
|
87
|
+
def autolink(link, _link_type)
|
88
|
+
pastel.blue(link)
|
89
|
+
end
|
90
|
+
|
91
|
+
def codespan(code)
|
92
|
+
code(code)
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
def surround_with_line_breaks(text, prepend_count, append_count)
|
98
|
+
text = clear_surrounding_line_breaks(text)
|
99
|
+
(new_line * prepend_count) << text << (new_line * append_count)
|
100
|
+
end
|
101
|
+
|
102
|
+
def clear_surrounding_line_breaks(text)
|
103
|
+
text.sub(/\A[\r\n]+/, '').sub(/[\r\n]+\z/, '')
|
104
|
+
end
|
105
|
+
|
106
|
+
def indent(text)
|
107
|
+
text.strip
|
108
|
+
.gsub(new_line, "#{new_line}#{LIST_INDENTATION}")
|
109
|
+
.prepend(LIST_INDENTATION)
|
110
|
+
end
|
111
|
+
|
112
|
+
def enumerate_list(text)
|
113
|
+
text.gsub(LIST_ORDERED_ITEM_PREFIX).with_index do |_, i|
|
114
|
+
"#{i + 1}#{LIST_ORDERED_ITEM_CHAR}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def new_line
|
119
|
+
"\n"
|
120
|
+
end
|
121
|
+
|
122
|
+
def code(text)
|
123
|
+
pastel.green(text.chomp)
|
124
|
+
end
|
125
|
+
|
126
|
+
def labeled_hrule(text)
|
127
|
+
text = (text || '').to_s.upcase
|
128
|
+
text = text.center(10, ' ') unless text.empty?
|
129
|
+
text = text.center(BLOCK_MAX_WITH, BLOCK_DELIMITER)
|
130
|
+
|
131
|
+
surround_with_line_breaks(text, 1, 1)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/misfortune.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require 'misfortune/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'misfortune'
|
8
|
+
spec.version = Misfortune::VERSION
|
9
|
+
spec.date = '2016-03-24'
|
10
|
+
spec.summary = 'Unmaintainable fortune cookies'
|
11
|
+
spec.description = '"How To Write Unmaintainable Code" turned into fortune cookies'
|
12
|
+
spec.authors = ['Nikolay Bekirov']
|
13
|
+
spec.email = 'nbekirov@gmail.com'
|
14
|
+
spec.homepage = 'http://rubygems.org/gems/misfortune'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.bindir = 'bin'
|
18
|
+
spec.executables = ['misfortune']
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
21
|
+
f =~ %r{^(?:
|
22
|
+
spec.*
|
23
|
+
|Rakefile
|
24
|
+
|\.gitignore
|
25
|
+
|\.rubocop.yml
|
26
|
+
|\.rspec
|
27
|
+
|\.travis.yml
|
28
|
+
)$}x
|
29
|
+
end
|
30
|
+
|
31
|
+
spec.add_runtime_dependency('redcarpet', '~> 3.3')
|
32
|
+
spec.add_runtime_dependency('pastel', '~> 0.6')
|
33
|
+
spec.add_runtime_dependency('thor', '~> 0.19')
|
34
|
+
spec.add_development_dependency('rake', '~> 11.1')
|
35
|
+
spec.add_development_dependency('rspec', '~> 3.4')
|
36
|
+
spec.add_development_dependency('simplecov', '~> 0.11')
|
37
|
+
spec.add_development_dependency('bundler', '~> 1.11')
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: misfortune
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nikolay Bekirov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redcarpet
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pastel
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.19'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.19'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '11.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '11.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.4'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.4'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.11'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.11'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: bundler
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.11'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.11'
|
111
|
+
description: '"How To Write Unmaintainable Code" turned into fortune cookies'
|
112
|
+
email: nbekirov@gmail.com
|
113
|
+
executables:
|
114
|
+
- misfortune
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- Gemfile
|
119
|
+
- README.md
|
120
|
+
- bin/misfortune
|
121
|
+
- bin/setup
|
122
|
+
- data/source.md
|
123
|
+
- lib/misfortune.rb
|
124
|
+
- lib/misfortune/cli/binge_command.rb
|
125
|
+
- lib/misfortune/cli/random_command.rb
|
126
|
+
- lib/misfortune/cli/runner.rb
|
127
|
+
- lib/misfortune/cookie_jar.rb
|
128
|
+
- lib/misfortune/flavor.rb
|
129
|
+
- lib/misfortune/render/terminal.rb
|
130
|
+
- lib/misfortune/version.rb
|
131
|
+
- misfortune.gemspec
|
132
|
+
homepage: http://rubygems.org/gems/misfortune
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.6.2
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Unmaintainable fortune cookies
|
156
|
+
test_files: []
|