tty-file 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1b396379259eca3c11fd09a27eb97b9a777ae747
4
- data.tar.gz: c6094ec23477f0ab1e36af36f507d0b36f110ef1
3
+ metadata.gz: 23702ac1a40d811c8c23a524265585b0f6fecb26
4
+ data.tar.gz: fdc10c2af852b2c6d935d81439e90c54eaa2550b
5
5
  SHA512:
6
- metadata.gz: 45cbe892f8379b9a81f3e220aa874a6d49a06097616c826f917972663c681e4faf72b0c06c28727716eda35613d51e5669799f98bcf7e075fe742b02396e865c
7
- data.tar.gz: 087d20a6a7100e30c5c419a80534f51f88ce954a69dbf76f3a687e82d52dddd6b54cc8472731ee8830d9cfdbb58efeb7e550dc04e131728a1a9e7adece58089d
6
+ metadata.gz: 805acf272babab1d6dd610e500502573a2d85ab0c1ed738cde3974fe03f4134b5a447314c8f44ed7da2f8ed26a88f0060ea6547bae8f3c40a177a9ea99ab0639
7
+ data.tar.gz: 59f161b5ba098f482a2de30a1cbbda0dd42bf63509f0d7118e37c36af0e94f31a0c73cefb8a0854213259126c4d5df9e903c54f7e94aeb91d8399acd3fdcd907
@@ -8,17 +8,15 @@ rvm:
8
8
  - 2.1.10
9
9
  - 2.2.5
10
10
  - 2.3.1
11
- - 2.4.0
11
+ - 2.4.1
12
12
  - ruby-head
13
13
  - jruby-9.1.1.0
14
- - rbx-3
15
14
  env:
16
15
  global:
17
16
  - JRUBY_OPTS=''
18
17
  matrix:
19
18
  allow_failures:
20
19
  - rvm: ruby-head
21
- - rvm: rbx-3
22
20
  - rvm: jruby-9.1.1.0
23
21
  fast_finish: true
24
22
  branches:
@@ -1,5 +1,18 @@
1
1
  # Change log
2
2
 
3
+ ## [v0.4.0] - 2017-09-16
4
+
5
+ ### Added
6
+ * Add tail_file for reading a given number of lines from end of a file
7
+
8
+ ### Changed
9
+ * Change api calls to accept :color option for disabling/coloring log status
10
+ * Update tty-prompt dependency
11
+
12
+ ### Fixed
13
+ * Fix #log_status to properly handle wrapping of keywords in color
14
+ * Fix #binary? to work correctly on Windows
15
+
3
16
  ## [v0.3.0] - 2017-03-26
4
17
 
5
18
  ### Changed
@@ -32,6 +45,7 @@
32
45
 
33
46
  * Initial implementation and release
34
47
 
48
+ [v0.4.0]: https://github.com/piotrmurach/tty-file/compare/v0.3.0...v0.4.0
35
49
  [v0.3.0]: https://github.com/piotrmurach/tty-file/compare/v0.2.1...v0.3.0
36
50
  [v0.2.1]: https://github.com/piotrmurach/tty-file/compare/v0.2.0...v0.2.1
37
51
  [v0.2.0]: https://github.com/piotrmurach/tty-file/compare/v0.1.0...v0.2.0
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # TTY::File [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
2
+
2
3
  [![Gem Version](https://badge.fury.io/rb/tty-file.svg)][gem]
3
4
  [![Build Status](https://secure.travis-ci.org/piotrmurach/tty-file.svg?branch=master)][travis]
5
+ [![Build status](https://ci.appveyor.com/api/projects/status/og69rn550s4mt1q3?svg=true)][appveyor]
4
6
  [![Code Climate](https://codeclimate.com/github/piotrmurach/tty-file/badges/gpa.svg)][codeclimate]
5
7
  [![Coverage Status](https://coveralls.io/repos/github/piotrmurach/tty-file/badge.svg)][coverage]
6
8
  [![Inline docs](http://inch-ci.org/github/piotrmurach/tty-file.svg?branch=master)][inchpages]
@@ -8,6 +10,7 @@
8
10
  [gitter]: https://gitter.im/piotrmurach/tty
9
11
  [gem]: http://badge.fury.io/rb/tty-file
10
12
  [travis]: http://travis-ci.org/piotrmurach/tty-file
13
+ [appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-file
11
14
  [codeclimate]: https://codeclimate.com/github/piotrmurach/tty-file
12
15
  [coverage]: https://coveralls.io/github/piotrmurach/tty-file
13
16
  [inchpages]: http://inch-ci.org/github/piotrmurach/tty-file
@@ -52,6 +55,7 @@ Or install it yourself as:
52
55
  * [2.12. append_to_file](#212-apend_to_file)
53
56
  * [2.13. prepend_to_file](#213-prepend_to_file)
54
57
  * [2.14. remove_file](#214-remove_file)
58
+ * [2.15. tail_file](#215-tail_file)
55
59
 
56
60
  ## 1. Usage
57
61
 
@@ -323,6 +327,12 @@ TTY::File.download_file("https://gist.github.com/4701967", "doc/README.md", limi
323
327
 
324
328
  Inject content into a file at a given location
325
329
 
330
+ ```ruby
331
+ TTY::File.inject_into_file 'filename.rb', "text to add", after: "Code below this line\n"
332
+ ```
333
+
334
+ or using a block
335
+
326
336
  ```ruby
327
337
  TTY::File.inject_into_file 'filename.rb', after: "Code below this line\n" do
328
338
  "text to add"
@@ -393,6 +403,29 @@ You can also pass in `:force` to remove file ignoring any errors:
393
403
  TTY::File.remove_file 'doc/README.md', force: true
394
404
  ```
395
405
 
406
+ ### 2.15. tail_file
407
+
408
+ To read the last 10 lines from a file do:
409
+
410
+ ```ruby
411
+ TTY::File.tail_file 'doc/README.md'
412
+ # => ['## Copyright', 'Copyright (c) 2016-2017', ...]
413
+ ```
414
+
415
+ You can also pass a block:
416
+
417
+ ```ruby
418
+ TTY::File.tail_file('doc/README.md') do |line|
419
+ puts line
420
+ end
421
+ ```
422
+
423
+ To change how many lines are read pass a second argument:
424
+
425
+ ```ruby
426
+ TTY::File.tail_file('doc/README.md', 15)
427
+ ```
428
+
396
429
  ## Development
397
430
 
398
431
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,25 @@
1
+ ---
2
+ install:
3
+ - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
4
+ - ruby --version
5
+ - gem --version
6
+ - bundle install
7
+ build: off
8
+ test_script:
9
+ - bundle exec rake ci
10
+ environment:
11
+ matrix:
12
+ - ruby_version: "193"
13
+ - ruby_version: "200"
14
+ - ruby_version: "200-x64"
15
+ - ruby_version: "21"
16
+ - ruby_version: "21-x64"
17
+ - ruby_version: "22"
18
+ - ruby_version: "22-x64"
19
+ - ruby_version: "23"
20
+ - ruby_version: "23-x64"
21
+ - ruby_version: "24"
22
+ - ruby_version: "24-x64"
23
+ matrix:
24
+ allow_failures:
25
+ - ruby_version: "193"
@@ -10,6 +10,7 @@ require_relative 'file/create_file'
10
10
  require_relative 'file/digest_file'
11
11
  require_relative 'file/download_file'
12
12
  require_relative 'file/differ'
13
+ require_relative 'file/read_backward_file'
13
14
  require_relative 'file/version'
14
15
 
15
16
  module TTY
@@ -51,8 +52,8 @@ module TTY
51
52
  #
52
53
  # @api public
53
54
  def binary?(relative_path)
54
- bytes = ::File.stat(relative_path).blksize
55
- bytes = 4096 if bytes > 4096
55
+ bytes = ::File.new(relative_path).size
56
+ bytes = 2**12 if bytes > 2**12
56
57
  buffer = ::File.read(relative_path, bytes, 0) || ''
57
58
  buffer = buffer.force_encoding(Encoding.default_external)
58
59
  begin
@@ -122,7 +123,8 @@ module TTY
122
123
  end
123
124
  end
124
125
  end
125
- log_status(:chmod, relative_path, options.fetch(:verbose, true), :green)
126
+ log_status(:chmod, relative_path, options.fetch(:verbose, true),
127
+ options.fetch(:color, :green))
126
128
  ::FileUtils.chmod_R(mode, relative_path) unless options[:noop]
127
129
  end
128
130
  module_function :chmod
@@ -162,7 +164,8 @@ module TTY
162
164
  path = parent.nil? ? dir : ::File.join(parent, dir)
163
165
  unless ::File.exist?(path)
164
166
  ::FileUtils.mkdir_p(path)
165
- log_status(:create, path, options.fetch(:verbose, true), :green)
167
+ log_status(:create, path, options.fetch(:verbose, true),
168
+ options.fetch(:color, :green))
166
169
  end
167
170
 
168
171
  files.each do |filename, contents|
@@ -359,7 +362,7 @@ module TTY
359
362
  end
360
363
 
361
364
  log_status(:diff, "#{file_a.path} - #{file_b.path}",
362
- options.fetch(:verbose, true), :green)
365
+ options.fetch(:verbose, true), options.fetch(:color, :green))
363
366
  return output if options[:noop]
364
367
 
365
368
  block_size = file_a.lstat.blksize
@@ -437,7 +440,8 @@ module TTY
437
440
  #
438
441
  # @api public
439
442
  def prepend_to_file(relative_path, *args, **options, &block)
440
- log_status(:prepend, relative_path, options.fetch(:verbose, true), :green)
443
+ log_status(:prepend, relative_path, options.fetch(:verbose, true),
444
+ options.fetch(:color, :green))
441
445
  options.merge!(before: /\A/, verbose: false)
442
446
  inject_into_file(relative_path, *(args << options), &block)
443
447
  end
@@ -459,7 +463,8 @@ module TTY
459
463
  #
460
464
  # @api public
461
465
  def append_to_file(relative_path, *args, **options, &block)
462
- log_status(:append, relative_path, options.fetch(:verbose, true), :green)
466
+ log_status(:append, relative_path, options.fetch(:verbose, true),
467
+ options.fetch(:color, :green))
463
468
  options.merge!(after: /\z/, verbose: false)
464
469
  inject_into_file(relative_path, *(args << options), &block)
465
470
  end
@@ -512,7 +517,8 @@ module TTY
512
517
 
513
518
  replace_in_file(relative_path, /#{match}/, content, options.merge(verbose: false))
514
519
 
515
- log_status(:inject, relative_path, options.fetch(:verbose, true), :green)
520
+ log_status(:inject, relative_path, options.fetch(:verbose, true),
521
+ options.fetch(:color, :green))
516
522
  end
517
523
  module_function :inject_into_file
518
524
 
@@ -541,7 +547,8 @@ module TTY
541
547
  contents = IO.read(relative_path)
542
548
  replacement = (block ? block[] : args[1..-1].join).gsub('\0', '')
543
549
 
544
- log_status(:replace, relative_path, options.fetch(:verbose, true), :green)
550
+ log_status(:replace, relative_path, options.fetch(:verbose, true),
551
+ options.fetch(:color, :green))
545
552
 
546
553
  return if options[:noop]
547
554
 
@@ -575,7 +582,8 @@ module TTY
575
582
  #
576
583
  # @api public
577
584
  def remove_file(relative_path, *args, **options)
578
- log_status(:remove, relative_path, options.fetch(:verbose, true), :red)
585
+ log_status(:remove, relative_path, options.fetch(:verbose, true),
586
+ options.fetch(:color, :red))
579
587
 
580
588
  return if options[:noop]
581
589
 
@@ -583,6 +591,51 @@ module TTY
583
591
  end
584
592
  module_function :remove_file
585
593
 
594
+ # Provide the last number of lines from a file
595
+ #
596
+ # @param [String] relative_path
597
+ # the relative path to a file
598
+ #
599
+ # @param [Integer] num_lines
600
+ # the number of lines to return from file
601
+ #
602
+ # @example
603
+ # tail_file 'filename'
604
+ # # => ['line 19', 'line20', ... ]
605
+ #
606
+ # @example
607
+ # tail_file 'filename', 15
608
+ # # => ['line 19', 'line20', ... ]
609
+ #
610
+ # @return [Array[String]]
611
+ #
612
+ # @api public
613
+ def tail_file(relative_path, num_lines = 10, **options, &block)
614
+ file = ::File.open(relative_path)
615
+ chunk_size = options.fetch(:chunk_size, 512)
616
+ line_sep = $/
617
+ lines = []
618
+ newline_count = 0
619
+
620
+ ReadBackwardFile.new(file, chunk_size).each_chunk do |chunk|
621
+ # look for newline index counting from right of chunk
622
+ while (nl_index = chunk.rindex(line_sep, (nl_index || chunk.size) - 1))
623
+ newline_count += 1
624
+ break if newline_count > num_lines || nl_index.zero?
625
+ end
626
+
627
+ if newline_count > num_lines
628
+ lines.insert(0, chunk[(nl_index + 1)..-1])
629
+ break
630
+ else
631
+ lines.insert(0, chunk)
632
+ end
633
+ end
634
+
635
+ lines.join.split(line_sep).each(&block).to_a
636
+ end
637
+ module_function :tail_file
638
+
586
639
  # Escape glob character in a path
587
640
  #
588
641
  # @param [String] path
@@ -627,9 +680,12 @@ module TTY
627
680
  return unless verbose
628
681
 
629
682
  cmd = cmd.to_s.rjust(12)
630
- cmd = decorate(cmd, color) if color
683
+ if color
684
+ i = cmd.index(/[a-z]/)
685
+ cmd = cmd[0...i] + decorate(cmd[i..-1], color)
686
+ end
631
687
 
632
- message = "#{cmd} #{message}"
688
+ message = "#{cmd} #{message}"
633
689
  message += "\n" unless message.end_with?("\n")
634
690
 
635
691
  @output.print(message)
@@ -1,15 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'forwardable'
4
-
5
3
  module TTY
6
4
  module File
7
5
  class CreateFile
8
- extend Forwardable
9
-
10
- attr_reader :relative_path, :content, :options, :prompt
11
6
 
12
- def_delegators "@base", :log_status
7
+ attr_reader :base, :relative_path, :content, :options, :prompt
13
8
 
14
9
  def initialize(base, relative_path, content, options = {})
15
10
  @base = base
@@ -61,22 +56,29 @@ module TTY
61
56
  def detect_collision
62
57
  if exist?
63
58
  if identical?
64
- log_status(:identical, relative_path, options.fetch(:verbose, true), :blue)
59
+ notify(:identical, :blue)
65
60
  elsif options[:force]
66
- log_status(:force, relative_path, options.fetch(:verbose, true), :yellow)
61
+ notify(:force, :yellow)
67
62
  yield unless options[:noop]
68
63
  elsif options[:skip]
69
- log_status(:skip, relative_path, options.fetch(:verbose, true), :yellow)
64
+ notify(:skip, :yellow)
70
65
  else
71
- log_status(:collision, relative_path, options.fetch(:verbose, true), :red)
66
+ notify(:collision, :red)
72
67
  yield if file_collision(relative_path, content)
73
68
  end
74
69
  else
75
- log_status(:create, relative_path, options.fetch(:verbose, true), :green)
70
+ notify(:create, :green)
76
71
  yield unless options[:noop]
77
72
  end
78
73
  end
79
74
 
75
+ # Notify console about performed action
76
+ # @api private
77
+ def notify(name, color)
78
+ base.__send__(:log_status, name, relative_path,
79
+ options.fetch(:verbose, true), options.fetch(:color, color))
80
+ end
81
+
80
82
  # Display conflict resolution menu and gather answer
81
83
  #
82
84
  # @api private
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ class ReadBackwardFile
5
+ attr_reader :file,
6
+ :chunk_size
7
+
8
+ # Create a ReadBackwardFile
9
+ #
10
+ # @param [File] file
11
+ # the file to read backward from
12
+ # @param [Integer] chunk_size
13
+ # the chunk size used to step through the file backwards
14
+ #
15
+ # @api public
16
+ def initialize(file, chunk_size = 512)
17
+ @file = file
18
+ @chunk_size = chunk_size
19
+ @file_size = ::File.stat(file).size
20
+ end
21
+
22
+ # Read file in chunks
23
+ #
24
+ # @yield [String]
25
+ # the chunk from file content
26
+ #
27
+ # @api public
28
+ def each_chunk
29
+ file.seek(0, IO::SEEK_END)
30
+ while file.tell > 0
31
+ if file.tell < @chunk_size # don't read beyond file size
32
+ @chunk_size = file.tell
33
+ end
34
+ file.seek(-@chunk_size, IO::SEEK_CUR)
35
+ chunk = file.read(@chunk_size)
36
+ yield(chunk)
37
+ file.seek(-@chunk_size, IO::SEEK_CUR)
38
+ end
39
+ end
40
+ end # ReadBackwardFile
@@ -2,6 +2,6 @@
2
2
 
3
3
  module TTY
4
4
  module File
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
6
6
  end # File
7
7
  end # TTY
@@ -19,11 +19,11 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_dependency 'pastel', '~> 0.7.0'
23
- spec.add_dependency 'tty-prompt', '~> 0.12.0'
22
+ spec.add_dependency 'pastel', '~> 0.7.1'
23
+ spec.add_dependency 'tty-prompt', '~> 0.13.2'
24
24
  spec.add_dependency 'diff-lcs', '~> 1.3.0'
25
25
 
26
- spec.add_development_dependency 'bundler', '>= 1.5.0', '< 2.0'
26
+ spec.add_development_dependency 'bundler', '~> 1.5'
27
27
  spec.add_development_dependency 'rake', '~> 10.0'
28
28
  spec.add_development_dependency 'rspec', '~> 3.0'
29
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tty-file
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-03-26 00:00:00.000000000 Z
11
+ date: 2017-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pastel
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.7.0
19
+ version: 0.7.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.7.0
26
+ version: 0.7.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: tty-prompt
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.12.0
33
+ version: 0.13.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.12.0
40
+ version: 0.13.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: diff-lcs
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -56,22 +56,16 @@ dependencies:
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: 1.5.0
62
- - - "<"
59
+ - - "~>"
63
60
  - !ruby/object:Gem::Version
64
- version: '2.0'
61
+ version: '1.5'
65
62
  type: :development
66
63
  prerelease: false
67
64
  version_requirements: !ruby/object:Gem::Requirement
68
65
  requirements:
69
- - - ">="
70
- - !ruby/object:Gem::Version
71
- version: 1.5.0
72
- - - "<"
66
+ - - "~>"
73
67
  - !ruby/object:Gem::Version
74
- version: '2.0'
68
+ version: '1.5'
75
69
  - !ruby/object:Gem::Dependency
76
70
  name: rake
77
71
  requirement: !ruby/object:Gem::Requirement
@@ -116,6 +110,7 @@ files:
116
110
  - LICENSE.txt
117
111
  - README.md
118
112
  - Rakefile
113
+ - appveyor.yml
119
114
  - bin/console
120
115
  - bin/setup
121
116
  - lib/tty-file.rb
@@ -124,6 +119,7 @@ files:
124
119
  - lib/tty/file/differ.rb
125
120
  - lib/tty/file/digest_file.rb
126
121
  - lib/tty/file/download_file.rb
122
+ - lib/tty/file/read_backward_file.rb
127
123
  - lib/tty/file/version.rb
128
124
  - tasks/console.rake
129
125
  - tasks/coverage.rake