tty-file 0.6.0 → 0.7.0

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.
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