tty-file 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +18 -2
  3. data/README.md +58 -16
  4. data/Rakefile +1 -1
  5. data/lib/tty-file.rb +0 -2
  6. data/lib/tty/file.rb +35 -9
  7. data/lib/tty/file/create_file.rb +3 -1
  8. data/lib/tty/file/differ.rb +3 -2
  9. data/lib/tty/file/digest_file.rb +1 -1
  10. data/lib/tty/file/download_file.rb +3 -3
  11. data/lib/tty/file/read_backward_file.rb +0 -1
  12. data/lib/tty/file/version.rb +2 -2
  13. data/spec/fixtures/cli_app/%name%_cli.rb +2 -0
  14. data/spec/fixtures/cli_app/commands/subcommand.rb +2 -0
  15. data/spec/fixtures/cli_app/excluded/%name%_cli.rb +2 -0
  16. data/spec/fixtures/templates/%file_name%.rb +1 -0
  17. data/spec/fixtures/templates/unit_test.rb +1 -0
  18. data/spec/spec_helper.rb +90 -0
  19. data/spec/unit/append_to_file_spec.rb +85 -0
  20. data/spec/unit/binary_spec.rb +206 -0
  21. data/spec/unit/checksum_file_spec.rb +39 -0
  22. data/spec/unit/chmod_spec.rb +78 -0
  23. data/spec/unit/copy_directory_spec.rb +106 -0
  24. data/spec/unit/copy_file_spec.rb +157 -0
  25. data/spec/unit/create_directory_spec.rb +79 -0
  26. data/spec/unit/create_file_spec.rb +116 -0
  27. data/spec/unit/diff_spec.rb +93 -0
  28. data/spec/unit/differ/call_spec.rb +101 -0
  29. data/spec/unit/download_file_spec.rb +54 -0
  30. data/spec/unit/escape_glob_path_spec.rb +14 -0
  31. data/spec/unit/inject_into_file_spec.rb +162 -0
  32. data/spec/unit/prepend_to_file_spec.rb +98 -0
  33. data/spec/unit/remove_file_spec.rb +53 -0
  34. data/spec/unit/replace_in_file_spec.rb +126 -0
  35. data/spec/unit/tail_file_spec.rb +63 -0
  36. data/tasks/console.rake +1 -1
  37. data/tasks/coverage.rake +1 -1
  38. data/tasks/spec.rake +1 -1
  39. data/tty-file.gemspec +5 -4
  40. metadata +30 -13
  41. data/.gitignore +0 -10
  42. data/.rspec +0 -3
  43. data/.travis.yml +0 -26
  44. data/CODE_OF_CONDUCT.md +0 -49
  45. data/Gemfile +0 -9
  46. data/appveyor.yml +0 -26
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe TTY::File, '#diff' do
4
+ it "diffs two files" do
5
+ file_a = tmp_path('diff/file_a')
6
+ file_b = tmp_path('diff/file_b')
7
+
8
+ diff = TTY::File.diff(file_a, file_b, verbose: false)
9
+
10
+ expect(diff).to eq(strip_heredoc(<<-EOS
11
+ @@ -1,4 +1,4 @@
12
+ aaa
13
+ -bbb
14
+ +xxx
15
+ ccc
16
+ EOS
17
+ ))
18
+ end
19
+
20
+ it "diffs identical files" do
21
+ src_a = tmp_path('diff/file_a')
22
+
23
+ expect(TTY::File.diff(src_a, src_a, verbose: false)).to eq('')
24
+ end
25
+
26
+ it "diffs a file and a string" do
27
+ src_a = tmp_path('diff/file_a')
28
+ src_b = "aaa\nxxx\nccc\n"
29
+
30
+ diff = TTY::File.diff(src_a, src_b, verbose: false)
31
+
32
+ expect(diff).to eq(strip_heredoc(<<-EOS
33
+ @@ -1,4 +1,4 @@
34
+ aaa
35
+ -bbb
36
+ +xxx
37
+ ccc
38
+ EOS
39
+ ))
40
+ end
41
+
42
+ it "diffs two strings" do
43
+ file_a = "aaa\nbbb\nccc\n"
44
+ file_b = "aaa\nxxx\nccc\n"
45
+
46
+ diff = TTY::File.diff(file_a, file_b, verbose: false)
47
+
48
+ expect(diff).to eq(strip_heredoc(<<-EOS
49
+ @@ -1,4 +1,4 @@
50
+ aaa
51
+ -bbb
52
+ +xxx
53
+ ccc
54
+ EOS
55
+ ))
56
+ end
57
+
58
+ it "logs status" do
59
+ file_a = tmp_path('diff/file_a')
60
+ file_b = tmp_path('diff/file_b')
61
+
62
+ expect {
63
+ TTY::File.diff_files(file_a, file_b, verbose: true)
64
+ }.to output(%r{diff(.*)/diff/file_a(.*)/diff/file_b}).to_stdout_from_any_process
65
+ end
66
+
67
+ it "doesn't diff files when :noop option is given" do
68
+ file_a = tmp_path('diff/file_a')
69
+ file_b = tmp_path('diff/file_b')
70
+
71
+ diff = TTY::File.diff(file_a, file_b, verbose: false, noop: true)
72
+
73
+ expect(diff).to eq('')
74
+ end
75
+
76
+ it "doesn't diff if first file is too large" do
77
+ file_a = tmp_path('diff/file_a')
78
+ file_b = tmp_path('diff/file_b')
79
+
80
+ expect {
81
+ TTY::File.diff(file_a, file_b, threshold: 10)
82
+ }.to raise_error(ArgumentError, /file size of (.*) exceeds 10 bytes/)
83
+ end
84
+
85
+ it "doesn't diff binary files" do
86
+ file_a = tmp_path('blackhole.png')
87
+ file_b = tmp_path('diff/file_b')
88
+
89
+ expect {
90
+ TTY::File.diff(file_a, file_b)
91
+ }.to raise_error(ArgumentError, /is binary, diff output suppressed/)
92
+ end
93
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe TTY::File::Differ, '#call' do
4
+ it "diffs identical content" do
5
+ string_a = "aaa bbb ccc"
6
+
7
+ diff = TTY::File::Differ.new(string_a, string_a).call
8
+
9
+ expect(diff).to eq('')
10
+ end
11
+
12
+ it "diffs two files with single line content" do
13
+ string_a = "aaa bbb ccc"
14
+ string_b = "aaa xxx ccc"
15
+
16
+ diff = TTY::File::Differ.new(string_a, string_b).call
17
+
18
+ expect(diff).to eq(strip_heredoc(<<-EOS
19
+ @@ -1,2 +1,2 @@
20
+ -aaa bbb ccc
21
+ +aaa xxx ccc
22
+ EOS
23
+ ))
24
+ end
25
+
26
+ it "diffs two files with multi line content" do
27
+ string_a = "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\nkkk\nlll\n"
28
+ string_b = "aaa\nbbb\nzzz\nddd\neee\nfff\nggg\nhhh\niii\njjj\nwww\n"
29
+
30
+ diff = TTY::File::Differ.new(string_a, string_b).call
31
+
32
+ expect(diff).to eq(strip_heredoc(<<-EOS
33
+ @@ -1,6 +1,6 @@
34
+ aaa
35
+ bbb
36
+ -ccc
37
+ +zzz
38
+ ddd
39
+ eee
40
+ fff
41
+ @@ -8,6 +8,5 @@
42
+ hhh
43
+ iii
44
+ jjj
45
+ -kkk
46
+ -lll
47
+ +www
48
+ EOS
49
+ ))
50
+ end
51
+
52
+ it "handles differently encoded files" do
53
+ string_a = "wikipedia".encode('us-ascii')
54
+ string_b = "ウィキペディア".encode('UTF-8')
55
+
56
+ diff = TTY::File::Differ.new(string_a, string_b).call
57
+
58
+ expect(diff).to eq(strip_heredoc(<<-EOS
59
+ @@ -1,2 +1,2 @@
60
+ -wikipedia
61
+ +ウィキペディア
62
+ EOS
63
+ ))
64
+ end
65
+
66
+ it "accepts format" do
67
+ string_a = "aaa\nbbb\nccc\n"
68
+ string_b = "aaa\nxxx\nccc\n"
69
+
70
+ diff = TTY::File::Differ.new(string_a, string_b, format: :old).call
71
+
72
+ expect(diff).to eq(strip_heredoc(<<-EOS
73
+ 1,4c1,4
74
+ < aaa
75
+ < bbb
76
+ < ccc
77
+ ---
78
+ > aaa
79
+ > xxx
80
+ > ccc
81
+
82
+ EOS
83
+ ))
84
+ end
85
+
86
+ it "accepts context lines" do
87
+ string_a = "aaa\nbbb\nccc\nddd\neee\nfff"
88
+ string_b = "aaa\nbbb\nccc\nddd\nxxx\nfff"
89
+
90
+ diff = TTY::File::Differ.new(string_a, string_b, context_lines: 1).call
91
+
92
+ expect(diff).to eq(strip_heredoc(<<-EOS
93
+ @@ -4,3 +4,3 @@
94
+ ddd
95
+ -eee
96
+ +xxx
97
+ fff
98
+ EOS
99
+ ))
100
+ end
101
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe TTY::File, '#download_file' do
4
+ it "downloads a file from remote uri" do
5
+ body = "##Header1\nCopy text.\n"
6
+ stub_request(:get, "https://example.com/README.md").to_return(body: body)
7
+ path = tmp_path('doc/README.md')
8
+
9
+ TTY::File.download_file('https://example.com/README.md', path, verbose: false)
10
+
11
+ expect(File.read(path)).to eq(body)
12
+ end
13
+
14
+ it "yields content from remoe uri" do
15
+ body = "##Header1\nCopy text.\n"
16
+ stub_request(:get, "https://example.com/README.md").to_return(body: body)
17
+ path = tmp_path('doc/README.md')
18
+
19
+ TTY::File.download_file('https://example.com/README.md', path, verbose: false) do |content|
20
+ expect(a_request(:get, 'https://example.com/README.md')).to have_been_made
21
+ expect(content).to eq(body)
22
+ end
23
+ end
24
+
25
+ it "logs file operation" do
26
+ body = "##Header1\nCopy text.\n"
27
+ stub_request(:get, "https://example.com/README.md").to_return(body: body)
28
+ path = tmp_path('doc/README.md')
29
+
30
+ expect {
31
+ TTY::File.download_file('https://example.com/README.md', path)
32
+ }.to output(/create(.*)doc\/README.md/).to_stdout_from_any_process
33
+ end
34
+
35
+ it "specifies limit on redirects" do
36
+ stub_request(:get, "https://example.com/wrong").to_return(status: 302, headers: { location: 'https://example.com/wrong_again'})
37
+ stub_request(:get, "https://example.com/wrong_again").to_return(status: 302, headers: { location: 'https://example.com/README.md'})
38
+
39
+ path = tmp_path('doc/README.md')
40
+
41
+ expect {
42
+ TTY::File.download_file('https://example.com/wrong', path, verbose: false, limit: 1)
43
+ }.to raise_error(TTY::File::DownloadError)
44
+ end
45
+
46
+ it "copies the file from relative location if not URI" do
47
+ src_path = tmp_path('Gemfile')
48
+ dest_path = tmp_path('app/Gemfile')
49
+
50
+ TTY::File.get_file(src_path, dest_path, verbose: false)
51
+
52
+ exists_and_identical?('Gemfile', 'app/Gemfile')
53
+ end
54
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe TTY::File, '#escape_glob_path' do
4
+ {
5
+ "foo?" => "foo\\?",
6
+ "*foo" => "\\*foo",
7
+ "foo[bar]" => "foo\\[bar\\]",
8
+ "foo{bar}" => "foo\\{bar\\}"
9
+ }.each do |glob, escaped_glob|
10
+ it "escapes #{glob} to #{escaped_glob}" do
11
+ expect(TTY::File.escape_glob_path(glob)).to eq(escaped_glob)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe TTY::File, '#inject_into_file' do
4
+ it "injects content into file :before" do
5
+ file = tmp_path('Gemfile')
6
+ TTY::File.inject_into_file(file, "gem 'tty'\n",
7
+ before: "gem 'rack', '>=1.0'\n", verbose: false)
8
+
9
+ expect(File.read(file)).to eq([
10
+ "gem 'nokogiri'\n",
11
+ "gem 'rails', '5.0.0'\n",
12
+ "gem 'tty'\n",
13
+ "gem 'rack', '>=1.0'\n",
14
+ ].join)
15
+ end
16
+
17
+ it "injects content into file :after" do
18
+ file = tmp_path('Gemfile')
19
+
20
+ expect {
21
+ TTY::File.inject_into_file(file, "gem 'tty'", after: "gem 'rack', '>=1.0'\n")
22
+ }.to output(/inject/).to_stdout_from_any_process
23
+
24
+ expect(File.read(file)).to eq([
25
+ "gem 'nokogiri'\n",
26
+ "gem 'rails', '5.0.0'\n",
27
+ "gem 'rack', '>=1.0'\n",
28
+ "gem 'tty'"
29
+ ].join)
30
+ end
31
+
32
+ it "accepts content in block" do
33
+ file = tmp_path('Gemfile')
34
+
35
+ expect {
36
+ TTY::File.insert_into_file(file, after: "gem 'rack', '>=1.0'\n") do
37
+ "gem 'tty'"
38
+ end
39
+ }.to output(/inject/).to_stdout_from_any_process
40
+
41
+ expect(File.read(file)).to eq([
42
+ "gem 'nokogiri'\n",
43
+ "gem 'rails', '5.0.0'\n",
44
+ "gem 'rack', '>=1.0'\n",
45
+ "gem 'tty'"
46
+ ].join)
47
+ end
48
+
49
+ it "accepts many lines" do
50
+ file = tmp_path('Gemfile')
51
+
52
+ TTY::File.inject_into_file(file, "gem 'tty'\n", "gem 'loaf'",
53
+ after: "gem 'rack', '>=1.0'\n", verbose: false)
54
+
55
+ expect(File.read(file)).to eq([
56
+ "gem 'nokogiri'\n",
57
+ "gem 'rails', '5.0.0'\n",
58
+ "gem 'rack', '>=1.0'\n",
59
+ "gem 'tty'\n",
60
+ "gem 'loaf'"
61
+ ].join)
62
+ end
63
+
64
+ it "logs action" do
65
+ file = tmp_path('Gemfile')
66
+
67
+ expect {
68
+ TTY::File.inject_into_file(file, "gem 'tty'\n", "gem 'loaf'",
69
+ after: "gem 'rack', '>=1.0'\n", verbose: true)
70
+ }.to output(/\e\[32minject.*Gemfile/).to_stdout_from_any_process
71
+ end
72
+
73
+ it "logs action without color" do
74
+ file = tmp_path('Gemfile')
75
+
76
+ expect {
77
+ TTY::File.inject_into_file(file, "gem 'tty'\n", "gem 'loaf'",
78
+ after: "gem 'rack', '>=1.0'\n", verbose: true, color: false)
79
+ }.to output(/\s+inject.*Gemfile/).to_stdout_from_any_process
80
+ end
81
+
82
+ it "doesn't inject new content if already present" do
83
+ file = tmp_path('Gemfile')
84
+ TTY::File.inject_into_file(file, "gem 'tty'",
85
+ after: "gem 'rack', '>=1.0'\n", verbose: false)
86
+
87
+ expect(File.read(file)).to eq([
88
+ "gem 'nokogiri'\n",
89
+ "gem 'rails', '5.0.0'\n",
90
+ "gem 'rack', '>=1.0'\n",
91
+ "gem 'tty'"
92
+ ].join)
93
+
94
+ TTY::File.inject_into_file(file, "gem 'tty'",
95
+ after: "gem 'rack', '>=1.0'\n",
96
+ force: false, verbose: false)
97
+
98
+ expect(File.read(file)).to eq([
99
+ "gem 'nokogiri'\n",
100
+ "gem 'rails', '5.0.0'\n",
101
+ "gem 'rack', '>=1.0'\n",
102
+ "gem 'tty'"
103
+ ].join)
104
+ end
105
+
106
+ it "checks if a content can be safely injected" do
107
+ file = tmp_path('Gemfile')
108
+ TTY::File.safe_inject_into_file(file, "gem 'tty'",
109
+ after: "gem 'rack', '>=1.0'\n", verbose: false)
110
+ expect(::File.read(file)).to eq([
111
+ "gem 'nokogiri'\n",
112
+ "gem 'rails', '5.0.0'\n",
113
+ "gem 'rack', '>=1.0'\n",
114
+ "gem 'tty'"
115
+ ].join)
116
+ end
117
+
118
+ it "changes content already present if :force flag is true" do
119
+ file = tmp_path('Gemfile')
120
+
121
+ TTY::File.inject_into_file(file, "gem 'tty'\n",
122
+ before: "gem 'nokogiri'", verbose: false)
123
+
124
+ expect(File.read(file)).to eq([
125
+ "gem 'tty'\n",
126
+ "gem 'nokogiri'\n",
127
+ "gem 'rails', '5.0.0'\n",
128
+ "gem 'rack', '>=1.0'\n",
129
+ ].join)
130
+
131
+ TTY::File.inject_into_file(file, "gem 'tty'\n",
132
+ before: "gem 'nokogiri'", verbose: false, force: true)
133
+
134
+ expect(File.read(file)).to eq([
135
+ "gem 'tty'\n",
136
+ "gem 'tty'\n",
137
+ "gem 'nokogiri'\n",
138
+ "gem 'rails', '5.0.0'\n",
139
+ "gem 'rack', '>=1.0'\n",
140
+ ].join)
141
+ end
142
+
143
+ it "fails to inject into non existent file" do
144
+ file = tmp_path('unknown')
145
+
146
+ expect {
147
+ TTY::File.inject_into_file(file, "gem 'tty'", after: "gem 'rack', '>=1.0'\n")
148
+ }.to raise_error(ArgumentError, /File path (.)* does not exist/)
149
+ end
150
+
151
+ it "doesn't change content when :noop flag is true" do
152
+ file = tmp_path('Gemfile')
153
+ TTY::File.inject_into_file(file, "gem 'tty'\n",
154
+ before: "gem 'nokogiri'", verbose: false, noop: true)
155
+
156
+ expect(File.read(file)).to eq([
157
+ "gem 'nokogiri'\n",
158
+ "gem 'rails', '5.0.0'\n",
159
+ "gem 'rack', '>=1.0'\n",
160
+ ].join)
161
+ end
162
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe TTY::File, '#prepend_to_file' do
4
+ it "appends to file" do
5
+ file = tmp_path('Gemfile')
6
+ result = TTY::File.prepend_to_file(file, "gem 'tty'\n", verbose: false)
7
+ expect(result).to eq(true)
8
+ expect(File.read(file)).to eq([
9
+ "gem 'tty'\n",
10
+ "gem 'nokogiri'\n",
11
+ "gem 'rails', '5.0.0'\n",
12
+ "gem 'rack', '>=1.0'\n",
13
+ ].join)
14
+ end
15
+
16
+ it "prepends multiple lines to file" do
17
+ file = tmp_path('Gemfile')
18
+ TTY::File.prepend_to_file(file, "gem 'tty'\n", "gem 'rake'\n", verbose: false)
19
+ expect(File.read(file)).to eq([
20
+ "gem 'tty'\n",
21
+ "gem 'rake'\n",
22
+ "gem 'nokogiri'\n",
23
+ "gem 'rails', '5.0.0'\n",
24
+ "gem 'rack', '>=1.0'\n",
25
+ ].join)
26
+ end
27
+
28
+ it "prepends content in a block" do
29
+ file = tmp_path('Gemfile')
30
+ TTY::File.prepend_to_file(file, verbose: false) { "gem 'tty'\n"}
31
+ expect(File.read(file)).to eq([
32
+ "gem 'tty'\n",
33
+ "gem 'nokogiri'\n",
34
+ "gem 'rails', '5.0.0'\n",
35
+ "gem 'rack', '>=1.0'\n",
36
+ ].join)
37
+ end
38
+
39
+ it "doesn't prepend if already present" do
40
+ file = tmp_path('Gemfile')
41
+ TTY::File.prepend_to_file(file, "gem 'nokogiri'\n", force: false, verbose: false)
42
+ expect(::File.read(file)).to eq([
43
+ "gem 'nokogiri'\n",
44
+ "gem 'rails', '5.0.0'\n",
45
+ "gem 'rack', '>=1.0'\n",
46
+ ].join)
47
+ end
48
+
49
+ it "checks if a content can be safely prepended" do
50
+ file = tmp_path('Gemfile')
51
+ TTY::File.safe_prepend_to_file(file, "gem 'nokogiri'\n", verbose: false)
52
+ expect(::File.read(file)).to eq([
53
+ "gem 'nokogiri'\n",
54
+ "gem 'rails', '5.0.0'\n",
55
+ "gem 'rack', '>=1.0'\n",
56
+ ].join)
57
+ end
58
+
59
+ it "doesn't prepend if already present for multiline content" do
60
+ file = tmp_path('Gemfile')
61
+ TTY::File.prepend_to_file(file, "gem 'nokogiri'\n", verbose: false)
62
+ TTY::File.prepend_to_file(file, "gem 'nokogiri'\n", "gem 'nokogiri'\n", force: false, verbose: false)
63
+ expect(::File.read(file)).to eq([
64
+ "gem 'nokogiri'\n",
65
+ "gem 'nokogiri'\n",
66
+ "gem 'rails', '5.0.0'\n",
67
+ "gem 'rack', '>=1.0'\n",
68
+ ].join)
69
+ end
70
+
71
+ it "prepends multiple times if forced" do
72
+ file = tmp_path('Gemfile')
73
+ TTY::File.prepend_to_file(file, "gem 'nokogiri'\n", force: true, verbose: false)
74
+ TTY::File.prepend_to_file(file, "gem 'nokogiri'\n", "gem 'nokogiri'\n", force: true, verbose: false)
75
+ expect(::File.read(file)).to eq([
76
+ "gem 'nokogiri'\n",
77
+ "gem 'nokogiri'\n",
78
+ "gem 'nokogiri'\n",
79
+ "gem 'nokogiri'\n",
80
+ "gem 'rails', '5.0.0'\n",
81
+ "gem 'rack', '>=1.0'\n"
82
+ ].join)
83
+ end
84
+
85
+ it "logs action" do
86
+ file = tmp_path('Gemfile')
87
+ expect {
88
+ TTY::File.prepend_to_file(file, "gem 'tty'")
89
+ }.to output(/\e\[32mprepend\e\[0m.*Gemfile/).to_stdout_from_any_process
90
+ end
91
+
92
+ it "logs action without color" do
93
+ file = tmp_path('Gemfile')
94
+ expect {
95
+ TTY::File.prepend_to_file(file, "gem 'tty'", color: false)
96
+ }.to output(/\s+prepend.*Gemfile/).to_stdout_from_any_process
97
+ end
98
+ end