code_snippet 0.2.6

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,52 @@
1
+ require 'code_snippet/cli/commands'
2
+ require 'code_snippet/cli/presenters'
3
+
4
+ require 'logger'
5
+
6
+ module CodeSnippet
7
+ # Command line interface helpers and actions
8
+ module CLI
9
+ # CLI Helpers
10
+ class <<self
11
+ ##
12
+ # Retrieves snippet dir from environment
13
+ #
14
+ def snip_dir
15
+ @snippet_dir = ENV['SNIPPET_DIR']
16
+ raise 'SNIPPET_DIR environment variable not set' unless @snippet_dir
17
+ unless File.exist?(@snippet_dir)
18
+ raise "SNIPPET_DIR #{@snippet_dir} does not exist"
19
+ end
20
+
21
+ @snippet_dir
22
+ end
23
+
24
+ ##
25
+ # Creates logger for printing messages
26
+ #
27
+ def logger
28
+ @logger ||= Logger.new(STDOUT)
29
+ @logger.formatter = proc do |_sev, _time, _prog, msg|
30
+ "#{msg}\n"
31
+ end
32
+
33
+ @logger
34
+ end
35
+
36
+ ##
37
+ # Prints command line message to CLI
38
+ #
39
+ def print_message(message)
40
+ logger.info(message)
41
+ end
42
+
43
+ ##
44
+ # Prints a message and then exits with given status code
45
+ #
46
+ def print_message_and_exit(message, exit_code = 1)
47
+ print_message(message)
48
+ exit(exit_code)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,50 @@
1
+ module CodeSnippet
2
+ # Manager looks after a set of snippets
3
+ class Manager
4
+ DEFAULT_QUERY = ->(_snip) { return true }
5
+
6
+ attr_reader :snippets
7
+
8
+ def initialize(snippet_dir)
9
+ @snippet_dir = snippet_dir
10
+ @snippets = []
11
+ end
12
+
13
+ def load_snippets
14
+ Dir.glob(File.join(@snippet_dir, '**', '*')).each do |file|
15
+ next if File.directory?(file)
16
+
17
+ @snippets << CodeSnippet::Snip.new_from_file(file)
18
+ end
19
+ end
20
+
21
+ def filter(query = DEFAULT_QUERY)
22
+ @snippets.select do |snip|
23
+ query.call(snip)
24
+ end
25
+ end
26
+
27
+ def find(search_term, lang = nil)
28
+ name_query = lambda do |snip|
29
+ snip.name.include?(search_term)
30
+ end
31
+
32
+ results = filter(name_query)
33
+
34
+ unless lang.nil?
35
+ results = results.select do |snip|
36
+ snip.ext == lang
37
+ end
38
+ end
39
+
40
+ results
41
+ end
42
+
43
+ def filter_by_extension(ext)
44
+ ext = ".#{ext}" unless ext.start_with?('.')
45
+
46
+ ext_query = ->(snip) { snip.ext == ext }
47
+ filter(ext_query)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,35 @@
1
+ module CodeSnippet
2
+ # Snip is a file with a code snippet
3
+ class Snip
4
+ attr_reader :path, :ext
5
+
6
+ def self.new_from_file(path)
7
+ new(
8
+ path,
9
+ File.basename(path),
10
+ File.extname(path)
11
+ )
12
+ end
13
+
14
+ def initialize(path, name, ext)
15
+ @path = path
16
+ @name = name
17
+ @ext = ext
18
+ end
19
+
20
+ def name
21
+ @name
22
+ .gsub(@ext, '')
23
+ end
24
+
25
+ def exist?
26
+ File.exist?(@path)
27
+ end
28
+
29
+ def content
30
+ raise 'cannot read snippet code' unless exist?
31
+
32
+ File.read(@path)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module CodeSnippet
2
+ VERSION = '0.2.6'.freeze
3
+ end
@@ -0,0 +1,7 @@
1
+ require 'code_snippet/version'
2
+ require 'code_snippet/manager'
3
+ require 'code_snippet/snip'
4
+
5
+ # Snippet is the namespace for snippet
6
+ module CodeSnippet
7
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CodeSnippet::CLI::Commands do
4
+ let(:snippet_dir) { 'path/to/snippets' }
5
+ let(:lang) { '.rb' }
6
+ let(:copy) { false }
7
+ let(:vars) { [] }
8
+
9
+ before do
10
+ allow(ENV)
11
+ .to receive(:[]).with('SNIPPET_DIR')
12
+ .and_return(snippet_dir)
13
+
14
+ allow(File)
15
+ .to receive(:exist?)
16
+ .with(snippet_dir)
17
+ .and_return(true)
18
+ end
19
+
20
+ describe '.show' do
21
+ end
22
+
23
+ describe '.list' do
24
+ let(:manager) { double(CodeSnippet::Manager) }
25
+ let(:lang) { nil }
26
+
27
+ let(:snip) { double(CodeSnippet::Snip) }
28
+ let(:filtered_snips) { [snip, snip] }
29
+ let(:all_snips) { [snip, snip, snip, snip] }
30
+
31
+ before do
32
+ allow(CodeSnippet::CLI).to receive(:snip_dir)
33
+ .and_return('path/to/snips')
34
+
35
+ allow(CodeSnippet::Manager)
36
+ .to receive(:new)
37
+ .and_return(manager)
38
+
39
+ allow(manager).to receive(:load_snippets)
40
+ allow(manager)
41
+ .to receive(:filter_by_extension)
42
+ .and_return(filtered_snips)
43
+
44
+ allow(manager)
45
+ .to receive(:snippets)
46
+ .and_return(all_snips)
47
+
48
+ allow(CodeSnippet::CLI::Presenters)
49
+ .to receive(:list_snippets)
50
+
51
+ described_class.list(lang, copy, vars)
52
+ end
53
+
54
+ it 'loads snippets' do
55
+ expect(manager).to have_received(:load_snippets)
56
+ end
57
+
58
+ it 'presents a list of snippets' do
59
+ expect(CodeSnippet::CLI::Presenters)
60
+ .to have_received(:list_snippets)
61
+ .with(all_snips)
62
+ end
63
+
64
+ context 'when language filter is applied' do
65
+ let(:lang) { '.rb' }
66
+
67
+ it 'presents a list of filtered snippets' do
68
+ expect(CodeSnippet::CLI::Presenters)
69
+ .to have_received(:list_snippets)
70
+ .with(filtered_snips)
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '.path' do
76
+ before do
77
+ allow(CodeSnippet::CLI)
78
+ .to receive(:print_message)
79
+ .and_return(nil)
80
+
81
+ described_class.path(lang, copy, vars)
82
+ end
83
+
84
+ it 'prints snippet dir' do
85
+ expect(CodeSnippet::CLI).to have_received(:print_message)
86
+ .with(snippet_dir)
87
+ end
88
+ end
89
+
90
+ describe '.version' do
91
+ before do
92
+ allow(CodeSnippet::CLI)
93
+ .to receive(:print_message)
94
+ .and_return(nil)
95
+
96
+ described_class.version(lang, copy, vars)
97
+ end
98
+
99
+ it 'prints snippet version' do
100
+ expect(CodeSnippet::CLI).to have_received(:print_message)
101
+ .with(CodeSnippet::VERSION)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CodeSnippet::CLI::Presenters do
4
+ let(:snippets) { [snip, snip] }
5
+
6
+ let(:snip) { double(CodeSnippet::Snip) }
7
+ let(:name) { 'snippet' }
8
+ let(:ext) { '.snip' }
9
+ let(:path) { 'path/to/snippet' }
10
+ let(:content) { 'snip-content' }
11
+
12
+ before do
13
+ allow(CodeSnippet::CLI).to receive(:print_message).and_return(double)
14
+ allow(snip).to receive(:name).and_return(name)
15
+ allow(snip).to receive(:ext).and_return(ext)
16
+ allow(snip).to receive(:path).and_return(path)
17
+ allow(snip).to receive(:content).and_return(content)
18
+ end
19
+ describe '.pick_from' do
20
+ let(:question) { 'are you sure?' }
21
+ let(:snips) { [snip, snip] }
22
+ let(:prompt) { double(TTY::Prompt) }
23
+
24
+ before do
25
+ allow(TTY::Prompt).to receive(:new).and_return(prompt)
26
+ allow(prompt).to receive(:select).and_return(path)
27
+ @choice = subject.pick_from(question, snips)
28
+ end
29
+
30
+ it 'asks which path' do
31
+ expect(prompt).to have_received(:select)
32
+ .with(question, [path, path])
33
+ end
34
+
35
+ it 'returns chosen path' do
36
+ expect(@choice).to eq snip
37
+ end
38
+ end
39
+
40
+ describe '.show' do
41
+ before do
42
+ described_class.show(snip)
43
+ end
44
+
45
+ it 'puts content to STDOUT' do
46
+ expect(CodeSnippet::CLI).to have_received(:print_message).with(content)
47
+ end
48
+ end
49
+
50
+ describe '.list_snippets' do
51
+ let(:table) { double(TTY::Table) }
52
+ before do
53
+ allow(TTY::Table).to receive(:new).and_return(table)
54
+ allow(table).to receive(:render)
55
+ described_class.list_snippets(snippets)
56
+ end
57
+
58
+ it 'sets up render' do
59
+ expect(TTY::Table).to have_received(:new).with(
60
+ %w[NAME LANG PATH],
61
+ [
62
+ [name, ext, path],
63
+ [name, ext, path]
64
+ ]
65
+ )
66
+ end
67
+
68
+ it 'renders table' do
69
+ expect(table).to have_received(:render).with(:ascii)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CodeSnippet::CLI do
4
+ let(:logger) { double(Logger) }
5
+ let(:message) { 'lorem ipsum' }
6
+
7
+ before do
8
+ allow(described_class).to receive(:exit).and_return(double)
9
+ end
10
+
11
+ describe '.snip_dir' do
12
+ let(:snippet_dir) { 'path/to/snippets' }
13
+ let(:exists) { true }
14
+
15
+ before do
16
+ allow(ENV)
17
+ .to receive(:[])
18
+ .with('SNIPPET_DIR')
19
+ .and_return(snippet_dir)
20
+
21
+ allow(File).to receive(:exist?).and_return(exists)
22
+ end
23
+
24
+ it 'returns path to snippets' do
25
+ expect(described_class.snip_dir).to eq snippet_dir
26
+ end
27
+
28
+ context 'when the environment variable is not set' do
29
+ let(:snippet_dir) { nil }
30
+
31
+ it 'raises error' do
32
+ expect do
33
+ described_class.snip_dir
34
+ end.to raise_error 'SNIPPET_DIR environment variable not set'
35
+ end
36
+ end
37
+
38
+ context 'when the snippet directory does not exist' do
39
+ let(:exists) { false }
40
+
41
+ it 'raises error' do
42
+ expect do
43
+ described_class.snip_dir
44
+ end.to raise_error "SNIPPET_DIR #{snippet_dir} does not exist"
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '.logger' do
50
+ before do
51
+ allow(Logger).to receive(:new).and_return(logger)
52
+ allow(logger).to receive(:formatter=)
53
+ @logger = subject.logger
54
+ end
55
+
56
+ it 'creates a new logger to STDOUT' do
57
+ expect(Logger).to have_received(:new).with(STDOUT)
58
+ end
59
+ end
60
+
61
+ describe '.print_message' do
62
+ let(:logger) { double(Logger) }
63
+
64
+ before do
65
+ allow(described_class).to receive(:logger).and_return(logger)
66
+ allow(logger).to receive(:info)
67
+ described_class.print_message(message)
68
+ end
69
+
70
+ it 'prints message to stdout' do
71
+ expect(logger).to have_received(:info).with(message)
72
+ end
73
+ end
74
+
75
+ describe '.print_message_and_exit' do
76
+ let(:exit_code) { 2 }
77
+
78
+ before do
79
+ allow(described_class).to receive(:print_message)
80
+ described_class.print_message_and_exit(message, exit_code)
81
+ end
82
+
83
+ it 'prints message' do
84
+ expect(described_class).to have_received(:print_message).with(message)
85
+ end
86
+
87
+ it 'exits with set status' do
88
+ expect(described_class).to have_received(:exit).with(exit_code)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,166 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CodeSnippet::Manager do
4
+ let(:snippet_dir) { 'path/to/snippets' }
5
+
6
+ subject do
7
+ described_class.new(snippet_dir)
8
+ end
9
+
10
+ describe '#load_snippets' do
11
+ let(:directory) { File.join(snippet_dir, 'path/to/dir') }
12
+ let(:file) { File.join(snippet_dir, 'path/to/dir/file') }
13
+
14
+ let(:file_snip) { double(CodeSnippet::Snip) }
15
+ let(:files) do
16
+ [
17
+ directory,
18
+ directory,
19
+ file,
20
+ file
21
+ ]
22
+ end
23
+
24
+ before do
25
+ allow(File).to receive(:directory?).with(directory)
26
+ .and_return(true)
27
+
28
+ allow(File).to receive(:directory?).with(file)
29
+ .and_return(false)
30
+
31
+ allow(Dir).to receive(:glob).and_return(files)
32
+ allow(CodeSnippet::Snip).to receive(:new_from_file)
33
+ .and_return(file_snip)
34
+
35
+ subject.load_snippets
36
+ end
37
+
38
+ it 'creates snips from files' do
39
+ expect(subject.snippets.count).to be 2
40
+
41
+ subject.snippets.each do |snip|
42
+ expect(snip).to eq file_snip
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#filter' do
48
+ let(:query) do
49
+ ->(snip) { snip == target_snip }
50
+ end
51
+
52
+ let(:snip) { double(CodeSnippet::Snip) }
53
+ let(:target_snip) { double(CodeSnippet::Snip) }
54
+
55
+ let(:snips) do
56
+ [
57
+ snip,
58
+ snip,
59
+ target_snip
60
+ ]
61
+ end
62
+
63
+ before do
64
+ subject.instance_variable_set(:@snippets, snips)
65
+ @result = subject.filter(query)
66
+ end
67
+
68
+ it 'finds target snip in set' do
69
+ expect(@result.count).to be 1
70
+ expect(@result.first).to eq target_snip
71
+ end
72
+
73
+ context 'when no query is defined' do
74
+ before do
75
+ @results = subject.filter
76
+ end
77
+
78
+ it 'returns everything' do
79
+ expect(@results.count).to eq 3
80
+ end
81
+ end
82
+ end
83
+
84
+ describe '#find' do
85
+ let(:search_term) { 'foo' }
86
+ let(:lang) { '.rb' }
87
+
88
+ let(:snip) do
89
+ CodeSnippet::Snip.new('path/to/snip.rb', 'snip.rb', '.rb')
90
+ end
91
+
92
+ let(:target_snip) do
93
+ CodeSnippet::Snip.new('path/to/snip.rb', 'foo.rb', '.rb')
94
+ end
95
+
96
+ let(:almost_target_snip) do
97
+ CodeSnippet::Snip.new('path/to/snip.rb', 'foo.go', '.go')
98
+ end
99
+
100
+ let(:snips) do
101
+ [
102
+ snip,
103
+ snip,
104
+ target_snip,
105
+ almost_target_snip
106
+ ]
107
+ end
108
+
109
+ before do
110
+ subject.instance_variable_set(:@snippets, snips)
111
+ @result = subject.find(search_term, lang)
112
+ end
113
+
114
+ it 'returns expected snip' do
115
+ expect(@result.count).to be 1
116
+ expect(@result.first).to eq target_snip
117
+ end
118
+
119
+ context 'when language filter is not provided' do
120
+ let(:lang) { nil }
121
+
122
+ it 'returns expected snips' do
123
+ expect(@result.count).to be 2
124
+ expect(@result[0]).to be target_snip
125
+ expect(@result[1]).to be almost_target_snip
126
+ end
127
+ end
128
+ end
129
+
130
+ describe '#filter_by_extension' do
131
+ let(:search_term) { 'foo' }
132
+ let(:lang) { '.rb' }
133
+
134
+ let(:snip) do
135
+ CodeSnippet::Snip.new('path/to/snip.rb', 'snip.go', '.go')
136
+ end
137
+
138
+ let(:target_snip) do
139
+ CodeSnippet::Snip.new('path/to/snip.rb', 'foo.rb', '.rb')
140
+ end
141
+
142
+ let(:another_target_snip) do
143
+ CodeSnippet::Snip.new('path/to/snip.rb', 'bar.rb', '.rb')
144
+ end
145
+
146
+ let(:snips) do
147
+ [
148
+ snip,
149
+ snip,
150
+ target_snip,
151
+ another_target_snip
152
+ ]
153
+ end
154
+
155
+ before do
156
+ subject.instance_variable_set(:@snippets, snips)
157
+ @result = subject.filter_by_extension(lang)
158
+ end
159
+
160
+ it 'returns files matching extension' do
161
+ expect(@result.count).to be 2
162
+ expect(@result[0]).to be target_snip
163
+ expect(@result[1]).to be another_target_snip
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CodeSnippet::Snip do
4
+ let(:file_name) { 'snippet-file' }
5
+ let(:file_ext) { '.ext' }
6
+ let(:snip_dir) { 'path/to/snippets' }
7
+ let(:path) { "#{snip_dir}/path/to/#{file_name}#{file_ext}" }
8
+
9
+ describe '.new_from_file' do
10
+ before do
11
+ allow(CodeSnippet::CLI).to receive(:snip_dir)
12
+ .and_return(snip_dir)
13
+
14
+ @snip = described_class.new_from_file(path)
15
+ end
16
+
17
+ it 'creates snip from path' do
18
+ expect(@snip.path).to eq path
19
+ expect(@snip.name).to eq file_name
20
+ expect(@snip.ext).to eq file_ext
21
+ end
22
+ end
23
+
24
+ subject { described_class.new_from_file(path) }
25
+
26
+ describe '#name' do
27
+ it 'returns file name without snip_dir or file extension' do
28
+ expect(subject.name).to eq file_name
29
+ end
30
+ end
31
+
32
+ describe '#exist?' do
33
+ let(:exists) { true }
34
+ before do
35
+ allow(File).to receive(:exist?)
36
+ .with(path)
37
+ .and_return(exists)
38
+ end
39
+
40
+ it 'returns true when file exists' do
41
+ expect(subject.exist?).to be true
42
+ end
43
+
44
+ context 'when file does not exist' do
45
+ let(:exists) { false }
46
+
47
+ it 'returns false' do
48
+ expect(subject.exist?).to be false
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#content' do
54
+ let(:exist) { true }
55
+ let(:content) { 'some-snippet' }
56
+
57
+ before do
58
+ allow(subject).to receive(:exist?).and_return(exist)
59
+ allow(File).to receive(:read)
60
+ .with(path)
61
+ .and_return(content)
62
+ end
63
+
64
+ it 'returns snippet file content' do
65
+ expect(subject.content).to eq content
66
+ end
67
+
68
+ context 'when file does not exist' do
69
+ let(:exist) { false }
70
+
71
+ it 'raises error' do
72
+ expect do
73
+ subject.content
74
+ end.to raise_error('cannot read snippet code')
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+ require 'pry'
5
+ require 'bundler/setup'
6
+
7
+ SimpleCov.start
8
+
9
+ SimpleCov.configure do
10
+ add_filter 'config'
11
+ add_filter 'spec'
12
+ add_filter 'vendor'
13
+ coverage_dir 'target/reports/coverage'
14
+ minimum_coverage 10
15
+ end
16
+
17
+ require 'code_snippet'
18
+ require 'code_snippet/cli'
19
+
20
+ RSpec.configure do |config|
21
+ config.example_status_persistence_file_path = '.rspec_status'
22
+ config.disable_monkey_patching!
23
+
24
+ config.expect_with :rspec do |c|
25
+ c.syntax = :expect
26
+ end
27
+ end