pleasant_path 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6e26d3eb1ea19b636f25d9920be3aeb772175ce
4
- data.tar.gz: 46c754d3523b1436d029fe0a0877e70a508becf7
3
+ metadata.gz: ddfbea700d9c72193add267fe9a09e88bc5d99ff
4
+ data.tar.gz: 7b5bce70e3faad80ac3296767a6cbd8b398a454e
5
5
  SHA512:
6
- metadata.gz: 35f15a1f476b2dc68a1979fe72df5feed7b7cf41949eb98391379a36d92a40d1a3d6c72ea193965401796fa59b3e9021e70448321c6c7c7573c3d19d65ad563a
7
- data.tar.gz: 69be2fb1dcfa1362aac1d56fedc5558b7800506ab1b5ae58c5b3e573cbc39188c0641323a0f1cdbe7f2396b6ecf67aca76d867169cecfb3c05ba28000ef8ac25
6
+ metadata.gz: fdf0eb05a7e27313ec2f0a9016319952c65a0931371b575fa4b72dd8959efc124db7272d3fd4c2d9bc35bde095839594110ce52be48de2ec467a6439f1b0a9bc
7
+ data.tar.gz: e67312af4aa40ed25954d05979983fe45a38f727c9810184e2a63eb45e7b6fb0c340ea5d765c10848143ad46cdccdd01ebefa199d06cbc576cc35fd0ae3df195
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # pleasant_path
2
2
 
3
3
  A [fluent API] for pleasant file IO, written as extensions to core Ruby
4
- objects. See method listing below or browse the [full documentation].
4
+ objects. See API listing below, or browse the [full documentation].
5
5
 
6
6
  [fluent API]: https://en.wikipedia.org/wiki/Fluent_interface
7
7
  [full documentation]: http://www.rubydoc.info/gems/pleasant_path/
@@ -10,65 +10,115 @@ objects. See method listing below or browse the [full documentation].
10
10
  ## Examples
11
11
 
12
12
  ```ruby
13
- # Dedup lines in a file
14
- "line_items.txt".path.edit_lines(&:uniq)
15
-
16
13
  # Filter lines across multiple files
17
14
  "logs/*.txt".glob.each do |log|
18
- log.read_lines.grep(/Error/).append_to_file('errors.txt')
15
+ log.read_lines.grep(/^ERROR /).append_to_file("errors.txt")
19
16
  end
17
+
18
+ # Dedup lines in a file
19
+ "names.txt".path.edit_lines(&:uniq)
20
20
  ```
21
21
 
22
22
 
23
- ## API Methods
23
+ ## Core API
24
+
25
+ The following methods are available:
26
+
27
+ - [Pathname](http://www.rubydoc.info/gems/pleasant_path/Pathname)
28
+ - [::NULL](http://www.rubydoc.info/gems/pleasant_path/Pathname#NULL-constant)
29
+ - [#^](http://www.rubydoc.info/gems/pleasant_path/Pathname:%5E)
30
+ - [#append_file](http://www.rubydoc.info/gems/pleasant_path/Pathname:append_file)
31
+ - [#append_lines](http://www.rubydoc.info/gems/pleasant_path/Pathname:append_lines)
32
+ - [#append_text](http://www.rubydoc.info/gems/pleasant_path/Pathname:append_text)
33
+ - [#common_path](http://www.rubydoc.info/gems/pleasant_path/Pathname:common_path)
34
+ - [#copy](http://www.rubydoc.info/gems/pleasant_path/Pathname:copy)
35
+ - [#copy_into](http://www.rubydoc.info/gems/pleasant_path/Pathname:copy_into)
36
+ - [#delete!](http://www.rubydoc.info/gems/pleasant_path/Pathname:delete%21)
37
+ - [#dir?](http://www.rubydoc.info/gems/pleasant_path/Pathname:dir%3F)
38
+ - [#dir_empty?](http://www.rubydoc.info/gems/pleasant_path/Pathname:dir_empty%3F)
39
+ - [#dirs](http://www.rubydoc.info/gems/pleasant_path/Pathname:dirs)
40
+ - [#dirs_r](http://www.rubydoc.info/gems/pleasant_path/Pathname:dirs_r)
41
+ - [#edit_lines](http://www.rubydoc.info/gems/pleasant_path/Pathname:edit_lines)
42
+ - [#edit_text](http://www.rubydoc.info/gems/pleasant_path/Pathname:edit_text)
43
+ - [#files](http://www.rubydoc.info/gems/pleasant_path/Pathname:files)
44
+ - [#files_r](http://www.rubydoc.info/gems/pleasant_path/Pathname:files_r)
45
+ - [#make_dir](http://www.rubydoc.info/gems/pleasant_path/Pathname:make_dir)
46
+ - [#make_dirname](http://www.rubydoc.info/gems/pleasant_path/Pathname:make_dirname)
47
+ - [#move](http://www.rubydoc.info/gems/pleasant_path/Pathname:move)
48
+ - [#move_into](http://www.rubydoc.info/gems/pleasant_path/Pathname:move_into)
49
+ - [#parentname](http://www.rubydoc.info/gems/pleasant_path/Pathname:parentname)
50
+ - [#read_lines](http://www.rubydoc.info/gems/pleasant_path/Pathname:read_lines)
51
+ - [#rename_basename](http://www.rubydoc.info/gems/pleasant_path/Pathname:rename_basename)
52
+ - [#rename_extname](http://www.rubydoc.info/gems/pleasant_path/Pathname:rename_extname)
53
+ - [#to_pathname](http://www.rubydoc.info/gems/pleasant_path/Pathname:to_pathname)
54
+ - [#touch_file](http://www.rubydoc.info/gems/pleasant_path/Pathname:touch_file)
55
+ - [#write_lines](http://www.rubydoc.info/gems/pleasant_path/Pathname:write_lines)
56
+ - [#write_text](http://www.rubydoc.info/gems/pleasant_path/Pathname:write_text)
57
+ - [String](http://www.rubydoc.info/gems/pleasant_path/String)
58
+ - [#/](http://www.rubydoc.info/gems/pleasant_path/String:%2F)
59
+ - [#^](http://www.rubydoc.info/gems/pleasant_path/String:%5E)
60
+ - [#append_to_file](http://www.rubydoc.info/gems/pleasant_path/String:append_to_file)
61
+ - [#glob](http://www.rubydoc.info/gems/pleasant_path/String:glob)
62
+ - [#path](http://www.rubydoc.info/gems/pleasant_path/String:path)
63
+ - [#to_pathname](http://www.rubydoc.info/gems/pleasant_path/String:to_pathname)
64
+ - [#write_to_file](http://www.rubydoc.info/gems/pleasant_path/String:write_to_file)
65
+ - [Array](http://www.rubydoc.info/gems/pleasant_path/Array)
66
+ - [#append_to_file](http://www.rubydoc.info/gems/pleasant_path/Array:append_to_file)
67
+ - [#write_to_file](http://www.rubydoc.info/gems/pleasant_path/Array:write_to_file)
68
+ - [File](http://www.rubydoc.info/gems/pleasant_path/File)
69
+ - [.common_path](http://www.rubydoc.info/gems/pleasant_path/File.common_path)
70
+ - [.edit_lines](http://www.rubydoc.info/gems/pleasant_path/File.edit_lines)
71
+ - [.edit_text](http://www.rubydoc.info/gems/pleasant_path/File.edit_text)
72
+ - [IO](http://www.rubydoc.info/gems/pleasant_path/IO)
73
+ - [#read_lines](http://www.rubydoc.info/gems/pleasant_path/IO:read_lines)
74
+ - [#write_lines](http://www.rubydoc.info/gems/pleasant_path/IO:write_lines)
75
+
76
+
77
+ ## JSON-related and YAML-related API
78
+
79
+ *pleasant_path* also includes methods for interacting with JSON and YAML
80
+ files, using the [JSON module] and [YAML module] that are part of Ruby's
81
+ standard library. Because Ruby does not load these modules by default,
82
+ *pleasant_path* does not load its JSON-related and YAML-related API by
83
+ default either. To load these *pleasant_path* APIs **and** the relevant
84
+ standard library modules, use:
85
+
86
+ ```ruby
87
+ require "pleasant_path/json"
88
+ require "pleasant_path/yaml"
89
+ ```
90
+
91
+ [JSON module]: https://ruby-doc.org/stdlib/libdoc/json/rdoc/JSON.html
92
+ [YAML module]: https://ruby-doc.org/stdlib/libdoc/yaml/rdoc/YAML.html
24
93
 
94
+ The following methods are available:
95
+
96
+ - Object
97
+ - [write_to_json](http://www.rubydoc.info/gems/pleasant_path/Object:write_to_json)
98
+ - [write_to_yaml](http://www.rubydoc.info/gems/pleasant_path/Object:write_to_yaml)
25
99
  - Pathname
26
- - [^](http://www.rubydoc.info/gems/pleasant_path/Pathname%3A%5E)
27
- - [append_file](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Aappend_file)
28
- - [append_lines](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Aappend_lines)
29
- - [append_text](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Aappend_text)
30
- - [delete!](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Adelete%21)
31
- - [dir_empty?](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Adir_empty%3F)
32
- - [dirs](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Adirs)
33
- - [dirs_r](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Adirs_r)
34
- - [edit_lines](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Aedit_lines)
35
- - [edit_text](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Aedit_text)
36
- - [files](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Afiles)
37
- - [files_r](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Afiles_r)
38
- - [make_dir](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Amake_dir)
39
- - [make_dirname](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Amake_dirname)
40
- - [move](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Amove)
41
- - [move_into](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Amove_into)
42
- - [parentname](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Aparentname)
43
- - [read_lines](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Aread_lines)
44
- - [to_pathname](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Ato_pathname)
45
- - [touch_file](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Atouch_file)
46
- - [write_lines](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Awrite_lines)
47
- - [write_text](http://www.rubydoc.info/gems/pleasant_path/Pathname%3Awrite_text)
48
- - String
49
- - [/](http://www.rubydoc.info/gems/pleasant_path/String%3A%2F)
50
- - [^](http://www.rubydoc.info/gems/pleasant_path/String%3A%5E)
51
- - [append_to_file](http://www.rubydoc.info/gems/pleasant_path/String%3Aappend_to_file)
52
- - [glob](http://www.rubydoc.info/gems/pleasant_path/String%3Aglob)
53
- - [to_pathname](http://www.rubydoc.info/gems/pleasant_path/String%3Ato_pathname)
54
- - [write_to_file](http://www.rubydoc.info/gems/pleasant_path/String%3Awrite_to_file)
55
- - Array
56
- - [append_to_file](http://www.rubydoc.info/gems/pleasant_path/Array%3Aappend_to_file)
57
- - [write_to_file](http://www.rubydoc.info/gems/pleasant_path/Array%3Awrite_to_file)
58
- - File
59
- - [edit_lines](http://www.rubydoc.info/gems/pleasant_path/File.edit_lines)
60
- - [edit_text](http://www.rubydoc.info/gems/pleasant_path/File.edit_text)
61
- - IO
62
- - [read_lines](http://www.rubydoc.info/gems/pleasant_path/IO%3Aread_lines)
63
- - [write_lines](http://www.rubydoc.info/gems/pleasant_path/IO%3Awrite_lines)
100
+ - [load_json](http://www.rubydoc.info/gems/pleasant_path/Pathname:load_json)
101
+ - [load_yaml](http://www.rubydoc.info/gems/pleasant_path/Pathname:load_yaml)
102
+ - [read_json](http://www.rubydoc.info/gems/pleasant_path/Pathname:read_json)
103
+ - [read_yaml](http://www.rubydoc.info/gems/pleasant_path/Pathname:read_yaml)
64
104
 
65
105
 
66
106
  ## Installation
67
107
 
68
- $ gem install pleasant_path
108
+ Install from [Ruby Gems](https://rubygems.org/gems/pleasant_path):
109
+
110
+ ```bash
111
+ $ gem install pleasant_path
112
+ ```
113
+
114
+ Then require in your Ruby script:
115
+
116
+ ```ruby
117
+ require "pleasant_path"
118
+ ```
69
119
 
70
120
 
71
- ## Development
121
+ ## Contributing
72
122
 
73
123
  Run `rake test` to run the tests. You can also run `rake irb` for an
74
124
  interactive prompt that pre-loads the project code.
@@ -76,4 +126,4 @@ interactive prompt that pre-loads the project code.
76
126
 
77
127
  ## License
78
128
 
79
- [MIT License](http://opensource.org/licenses/MIT)
129
+ [MIT License](https://opensource.org/licenses/MIT)
@@ -5,6 +5,10 @@ class Array
5
5
  # The file is overwritten if it already exists. Any necessary parent
6
6
  # directories are created if they do not exist.
7
7
  #
8
+ # @example
9
+ # [:one, :two].write_to_file("out.txt") # == [:one, :two]
10
+ # File.read("out.txt") # == "one\ntwo\n"
11
+ #
8
12
  # @param file [String, Pathname]
9
13
  # @return [Array]
10
14
  def write_to_file(file)
@@ -17,6 +21,12 @@ class Array
17
21
  # The file is created if it does not exist. Any necessary parent
18
22
  # directories are created if they do not exist.
19
23
  #
24
+ # @example
25
+ # [:one, :two].append_to_file("out.txt") # == [:one, :two]
26
+ # File.read("out.txt") # == "one\ntwo\n"
27
+ # [:three, :four].append_to_file("out.txt") # == [:three, :four]
28
+ # File.read("out.txt") # == "one\ntwo\nthree\nfour\n"
29
+ #
20
30
  # @param file [String, Pathname]
21
31
  # @return [Array]
22
32
  def append_to_file(file)
@@ -1,10 +1,42 @@
1
1
  class File
2
2
 
3
+ # Computes the longest path that every path in a list has in common.
4
+ #
5
+ # @example
6
+ # File.common_path(["a/b/x", "a/b/y", "a/b/z"]) # == "a/b/"
7
+ # File.common_path(["a/b/x", "a/b/y", "a/z"]) # == "a/"
8
+ # File.common_path(["a/b/x", "a/b/y", "a"]) # == "a"
9
+ #
10
+ # @param paths [Enumerable<String>]
11
+ # @return [String]
12
+ def self.common_path(paths)
13
+ return paths.first if paths.length <= 1
14
+ short, long = paths.minmax
15
+ i = 0
16
+ last = -1
17
+ while i < short.length && short[i] == long[i]
18
+ last = i if short[i] == "/".freeze
19
+ i += 1
20
+ end
21
+ short[0, i == short.length ? i : (last + 1)]
22
+ end
23
+
3
24
  # Reads from the specified file its contents as a string, and yields
4
25
  # the string to the given block for editing. Writes the return value
5
26
  # of the block back to the file, overwriting previous contents.
6
27
  # Returns the file's new contents.
7
28
  #
29
+ # @example update JSON data file
30
+ # File.read("data.json") # == '{"nested":{"key":"value"}}'
31
+ #
32
+ # File.edit_text("data.json") do |text|
33
+ # data = JSON.parse(text)
34
+ # data["nested"]["key"] = "new value"
35
+ # data.to_json
36
+ # end # == '{"nested":{"key":"new value"}}'
37
+ #
38
+ # File.read("data.json") # == '{"nested":{"key":"new value"}}'
39
+ #
8
40
  # @param filename [String, Pathname]
9
41
  # @yield [text] edits current file contents
10
42
  # @yieldparam text [String] current contents
@@ -15,6 +47,7 @@ class File
15
47
  text = yield f.read
16
48
  f.seek(0, IO::SEEK_SET)
17
49
  f.write(text)
50
+ f.truncate(f.pos)
18
51
  text
19
52
  end
20
53
  end
@@ -26,6 +59,14 @@ class File
26
59
  # characters to use for both reading and writing. Returns the array
27
60
  # of lines that comprises the file's new contents.
28
61
  #
62
+ # @example dedup lines of file
63
+ # File.read("entries.txt") # == "AAA\nBBB\nBBB\nCCC\nAAA\n"
64
+ #
65
+ # File.edit_lines("entries.txt", &:uniq)
66
+ # # == ["AAA", "BBB", "CCC"]
67
+ #
68
+ # File.read("entries.txt") # == "AAA\nBBB\nCCC\n"
69
+ #
29
70
  # @param filename [String, Pathname]
30
71
  # @yield [lines] edits current file contents
31
72
  # @yieldparam lines [Array<String>] current contents
@@ -36,6 +77,8 @@ class File
36
77
  lines = yield f.read_lines
37
78
  f.seek(0, IO::SEEK_SET)
38
79
  f.write_lines(lines)
80
+ f.truncate(f.pos)
81
+ lines
39
82
  end
40
83
  end
41
84
 
@@ -1,10 +1,18 @@
1
1
  class IO
2
2
 
3
- # Writes each string plus a succeeding new line character
4
- # (<code>$/</code>) to the IO. Returns the lines unmodified.
3
+ # Writes each object as a string plus a succeeding new line character
4
+ # (<code>$/</code>) to the IO. Returns the objects unmodified.
5
5
  #
6
- # @param lines [Array<String>]
7
- # @return [Array<String>]
6
+ # @example
7
+ # # NOTE File inherits from IO
8
+ # File.open("out.txt") do |file|
9
+ # file.write_lines([:one, :two]) # == [:one, :two]
10
+ # end # == [:one, :two]
11
+ #
12
+ # File.read("out.txt") # == "one\ntwo\n"
13
+ #
14
+ # @param lines [Enumerable<#to_s>]
15
+ # @return [Enumerable<#to_s>]
8
16
  def write_lines(lines)
9
17
  lines.each do |line|
10
18
  self.write(line)
@@ -16,11 +24,19 @@ class IO
16
24
 
17
25
  # Reads from the IO all lines, and returns them as an array,
18
26
  # end-of-line characters excluded. The <code>$/</code> global string
19
- # specifies what end-of-line characters to look for.
27
+ # specifies what end-of-line characters to exclude.
20
28
  #
21
29
  # (Not to be confused with +IO#readlines+ which retains end-of-line
22
30
  # characters in every string it returns.)
23
31
  #
32
+ # @example
33
+ # # NOTE File inherits from IO
34
+ # File.read("in.txt") # == "one\ntwo\n"
35
+ #
36
+ # File.open("in.txt") do |file|
37
+ # file.read_lines # == ["one", "two"]
38
+ # end # == ["one", "two"]
39
+ #
24
40
  # @return [Array<String>]
25
41
  def read_lines
26
42
  self.readlines.each(&:chomp!)
@@ -0,0 +1,27 @@
1
+ class Object
2
+
3
+ # Dumps the Object as JSON, and writes the JSON to the specified file.
4
+ # Returns the Object unmodified.
5
+ #
6
+ # For information about available options see
7
+ # {http://ruby-doc.org/stdlib/libdoc/json/rdoc/JSON.html#method-i-generate
8
+ # +JSON.generate+}.
9
+ #
10
+ # @example
11
+ # { "key" => "value" }.write_to_json("out.json") # == { "key" => "value" }
12
+ # File.read("out.json") # == '{"key":"value"}'
13
+ #
14
+ # @param file [String, Pathname]
15
+ # @param options [Hash]
16
+ # @return [self]
17
+ def write_to_json(file, options = {})
18
+ options = {
19
+ quirks_mode: true,
20
+ allow_nan: true,
21
+ }.merge(options)
22
+
23
+ file.to_pathname.write_text(JSON.generate(self, options))
24
+ self
25
+ end
26
+
27
+ end
@@ -0,0 +1,58 @@
1
+ class Pathname
2
+
3
+ # Reads the contents of the file indicated by the Pathname, and parses
4
+ # it as JSON. The returned result will be a basic Ruby data
5
+ # structure, namely, one of: +nil+, +true+, +false+, a +Numeric+, a
6
+ # +String+, an +Array+, or a +Hash+.
7
+ #
8
+ # For information about available options, see
9
+ # {http://ruby-doc.org/stdlib/libdoc/json/rdoc/JSON.html#method-i-parse
10
+ # +JSON.parse+}.
11
+ #
12
+ # @example
13
+ # File.write("in.json", '{"key": "value"}')
14
+ #
15
+ # Pathname.new("in.json").read_json # == { "key" => "value" }
16
+ #
17
+ # @param options [Hash]
18
+ # @return [nil, true, false, Numeric, String, Symbol, Array, Hash]
19
+ def read_json(options = {})
20
+ options = {
21
+ quirks_mode: true,
22
+ allow_nan: true,
23
+ max_nesting: false,
24
+ create_additions: false,
25
+ }.merge(options)
26
+
27
+ JSON.parse(self.read_text, options)
28
+ end
29
+
30
+ # Reads the contents of the file indicated by the Pathname, and parses
31
+ # it as JSON. The parser will use type information embedded in the
32
+ # JSON to deserialize custom types. This is *UNSAFE* for JSON from
33
+ # an untrusted source. To consume untrusted JSON, use
34
+ # {Pathname#read_json} instead.
35
+ #
36
+ # For information about available options, see
37
+ # {http://ruby-doc.org/stdlib/libdoc/json/rdoc/JSON.html#method-i-parse
38
+ # +JSON.parse+}.
39
+ #
40
+ # For information about serializing custom types to JSON, see the
41
+ # {https://github.com/flori/json/blob/master/README.md#more-examples
42
+ # JSON readme}.
43
+ #
44
+ # @example
45
+ # require "json/add/core" # provides Struct#to_json
46
+ # Point = Struct.new(:x, :y)
47
+ # point = Point.new(10, 20)
48
+ # File.write("in.json", point.to_json)
49
+ #
50
+ # Pathname.new("in.json").load_json # == Point.new(10, 20)
51
+ #
52
+ # @param options [Hash]
53
+ # @return deserialized object
54
+ def load_json(options = {})
55
+ self.open('r'){|f| JSON.load(f, nil, options) }
56
+ end
57
+
58
+ end
@@ -0,0 +1,4 @@
1
+ require "json"
2
+ require "pleasant_path"
3
+ require_relative "json/object"
4
+ require_relative "json/pathname"
@@ -1,7 +1,12 @@
1
1
  class Pathname
2
2
 
3
+ # {https://ruby-doc.org/core/File/Constants.html#NULL +File::NULL+} as
4
+ # a Pathname. On POSIX systems, this should be equivalent to
5
+ # +Pathname.new("/dev/null")+.
6
+ NULL = Pathname.new(File::NULL)
7
+
3
8
  # Returns the Pathname unmodified. Exists for parity with
4
- # +String#to_pathname+.
9
+ # {String#to_pathname}.
5
10
  #
6
11
  # @return [Pathname]
7
12
  def to_pathname
@@ -14,7 +19,7 @@ class Pathname
14
19
  # specified by the argument.
15
20
  #
16
21
  # @example
17
- # (Pathname.new("path/to/file1") ^ "file2").to_s #=> "path/to/file2"
22
+ # Pathname.new("path/to/file1") ^ "file2" # == Pathname.new("path/to/file2")
18
23
  #
19
24
  # @param sibling [Pathname, String]
20
25
  # @return [Pathname]
@@ -25,13 +30,34 @@ class Pathname
25
30
  # Returns the +basename+ of the Pathname's parent directory.
26
31
  #
27
32
  # @example
28
- # Pathname.new("path/to/file").parentname.to_s #=> "to"
33
+ # Pathname.new("path/to/file").parentname # == Pathname.new("to")
29
34
  #
30
35
  # @return [Pathname]
31
36
  def parentname
32
37
  self.dirname.basename
33
38
  end
34
39
 
40
+ # Computes the longest path that the Pathname and +other+ have in
41
+ # common. See also {File.common_path}.
42
+ #
43
+ # @example
44
+ # f1 = Pathname.new("dir1/file1")
45
+ # f2 = Pathname.new("dir1/subdir1/file2")
46
+ # f3 = Pathname.new("dir1/subdir1/file3")
47
+ # f4 = Pathname.new("dir2/file4")
48
+ #
49
+ # f1.common_path(f2) # == Pathname.new("dir1/")
50
+ # f2.common_path(f3) # == Pathname.new("dir1/subdir1/")
51
+ # f3.common_path(f4) # == Pathname.new("")
52
+ #
53
+ # [f1, f2, f3].reduce(&:common_path) # == Pathname.new("dir1/")
54
+ #
55
+ # @param other [Pathname]
56
+ # @return [Pathname]
57
+ def common_path(other)
58
+ File.common_path([self.to_s, other.to_s]).to_pathname
59
+ end
60
+
35
61
  # Alias of +Pathname#directory?+.
36
62
  #
37
63
  # @return [Boolean]
@@ -40,6 +66,13 @@ class Pathname
40
66
  # True if the directory indicated by the Pathname contains no other
41
67
  # directories or files.
42
68
  #
69
+ # @example
70
+ # FileUtils.mkdir("parent")
71
+ # FileUtils.mkdir("parent/dir1")
72
+ #
73
+ # Pathname.new("parent").dir_empty? # == false
74
+ # Pathname.new("parent/dir1").dir_empty? # == true
75
+ #
43
76
  # @return [Boolean]
44
77
  def dir_empty?
45
78
  self.children(false).empty?
@@ -49,6 +82,18 @@ class Pathname
49
82
  # directory indicated by the Pathname. Returned Pathnames are
50
83
  # prefixed by the original Pathname.
51
84
  #
85
+ # @example
86
+ # FileUtils.mkdir("parent")
87
+ # FileUtils.mkdir("parent/dir1")
88
+ # FileUtils.mkdir("parent/dir2")
89
+ # FileUtils.touch("parent/file1")
90
+ #
91
+ # Pathname.new("parent").dirs
92
+ # # == [
93
+ # # Pathname.new("parent/dir1"),
94
+ # # Pathname.new("parent/dir2")
95
+ # # ]
96
+ #
52
97
  # @return [Array<Pathname>]
53
98
  def dirs
54
99
  self.children.tap{|c| c.select!(&:dir?) }
@@ -58,6 +103,20 @@ class Pathname
58
103
  # directory indicated by the Pathname. Returned Pathnames are
59
104
  # prefixed by the original Pathname.
60
105
  #
106
+ # @example
107
+ # FileUtils.mkdir("parent")
108
+ # FileUtils.mkdir("parent/dir1")
109
+ # FileUtils.mkdir("parent/dir1/dir1")
110
+ # FileUtils.mkdir("parent/dir2")
111
+ # FileUtils.touch("parent/dir2/file1")
112
+ #
113
+ # Pathname.new("parent").dirs_r
114
+ # # == [
115
+ # # Pathname.new("parent/dir1"),
116
+ # # Pathname.new("parent/dir1/dir1"),
117
+ # # Pathname.new("parent/dir2")
118
+ # # ]
119
+ #
61
120
  # @return [Array<Pathname>]
62
121
  def dirs_r
63
122
  self.find.select(&:dir?).tap(&:shift)
@@ -67,6 +126,18 @@ class Pathname
67
126
  # indicated by the Pathname. Returned Pathnames are prefixed by the
68
127
  # original Pathname.
69
128
  #
129
+ # @example
130
+ # FileUtils.mkdir("parent")
131
+ # FileUtils.touch("parent/file1")
132
+ # FileUtils.touch("parent/file2")
133
+ # FileUtils.mkdir("parent/dir1")
134
+ #
135
+ # Pathname.new("parent").files
136
+ # # == [
137
+ # # Pathname.new("parent/file1"),
138
+ # # Pathname.new("parent/file2")
139
+ # # ]
140
+ #
70
141
  # @return [Array<Pathname>]
71
142
  def files
72
143
  self.children.tap{|c| c.select!(&:file?) }
@@ -76,6 +147,18 @@ class Pathname
76
147
  # indicated by the Pathname. Returned Pathnames are prefixed by the
77
148
  # original Pathname.
78
149
  #
150
+ # @example
151
+ # FileUtils.mkdir("parent")
152
+ # FileUtils.mkdir("parent/dir1")
153
+ # FileUtils.touch("parent/dir1/file1")
154
+ # FileUtils.touch("parent/file1")
155
+ #
156
+ # Pathname.new("parent").files_r
157
+ # # == [
158
+ # # Pathname.new("parent/dir1/file1"),
159
+ # # Pathname.new("parent/file1")
160
+ # # ]
161
+ #
79
162
  # @return [Array<Pathname>]
80
163
  def files_r
81
164
  self.find.select(&:file?)
@@ -83,6 +166,15 @@ class Pathname
83
166
 
84
167
  # Alias of +Pathname#mkpath+, but this method returns the Pathname.
85
168
  #
169
+ # @example
170
+ # Dir.exist?("path") # == false
171
+ # Dir.exist?("path/to") # == false
172
+ #
173
+ # Pathname.new("path/to").make_dir # == Pathname.new("path/to")
174
+ #
175
+ # Dir.exist?("path") # == true
176
+ # Dir.exist?("path/to") # == true
177
+ #
86
178
  # @return [Pathname]
87
179
  def make_dir
88
180
  self.mkpath
@@ -92,6 +184,16 @@ class Pathname
92
184
  # Creates the parent (+dirname+) directories of the Pathname if they
93
185
  # do not exist, and returns the Pathname.
94
186
  #
187
+ # @example
188
+ # Dir.exist?("path") # == false
189
+ # Dir.exist?("path/to") # == false
190
+ #
191
+ # Pathname.new("path/to/file").make_dirname # == Pathname.new("path/to/file")
192
+ #
193
+ # Dir.exist?("path") # == true
194
+ # Dir.exist?("path/to") # == true
195
+ # Dir.exist?("path/to/file") # == false
196
+ #
95
197
  # @return [Pathname]
96
198
  def make_dirname
97
199
  self.dirname.make_dir
@@ -103,6 +205,16 @@ class Pathname
103
205
  # the file and any necessary parent directories if they do not exist.
104
206
  # See also +FileUtils.touch+.
105
207
  #
208
+ # @example
209
+ # Dir.exist?("path") # == false
210
+ # Dir.exist?("path/to") # == false
211
+ #
212
+ # Pathname.new("path/to/file").touch_file # == Pathname.new("path/to/file")
213
+ #
214
+ # Dir.exist?("path") # == true
215
+ # Dir.exist?("path/to") # == true
216
+ # File.exist?("path/to/file") # == true
217
+ #
106
218
  # @return [Pathname]
107
219
  def touch_file
108
220
  self.make_dirname
@@ -114,28 +226,66 @@ class Pathname
114
226
  # and returns the Pathname. Similar to +Pathname#rmtree+, but does
115
227
  # not raise an exception if the file does not exist.
116
228
  #
229
+ # @example
230
+ # File.exist?("path/to/file") # == true
231
+ #
232
+ # Pathname.new("path").delete! # == Pathname.new("path")
233
+ #
234
+ # Dir.exist?("path") # == false
235
+ # Dir.exist?("path/to") # == false
236
+ # File.exist?("path/to/file") # == false
237
+ #
117
238
  # @return [Pathname]
118
239
  def delete!
119
240
  self.rmtree if self.exist?
120
241
  self
121
242
  end
122
243
 
123
- # Moves the file indicated by Pathname to the given destination, and
124
- # returns that destination as a Pathname. Creates any necessary
125
- # parent directories if they do not exist.
244
+ # Moves the file or directory indicated by the Pathname to the given
245
+ # destination, and returns that destination as a Pathname. Creates
246
+ # any necessary parent directories if they do not exist. See also
247
+ # +FileUtils.mv+.
248
+ #
249
+ # @example
250
+ # File.exist?("path/to/file") # == true
251
+ # Dir.exist?("some") # == false
252
+ # Dir.exist?("some/other") # == false
253
+ # File.exist?("some/other/thing") # == false
254
+ #
255
+ # Pathname.new("path/to/file").move("some/other/thing")
256
+ # # == Pathname.new("some/other/thing")
257
+ #
258
+ # File.exist?("path/to/file") # == false
259
+ # Dir.exist?("some") # == true
260
+ # Dir.exist?("some/other") # == true
261
+ # File.exist?("some/other/thing") # == true
126
262
  #
127
263
  # @param destination [Pathname, String]
128
264
  # @return [Pathname]
129
265
  def move(destination)
130
266
  destination = destination.to_pathname
131
267
  destination.make_dirname
132
- self.rename(destination)
268
+ FileUtils.mv(self, destination)
133
269
  destination
134
270
  end
135
271
 
136
- # Moves the file indicated by Pathname into the given directory, and
137
- # returns the resultant path to the file as a Pathname. Creates any
138
- # necessary parent directories if they do not exist.
272
+ # Moves the file or directory indicated by the Pathname into the given
273
+ # directory, and returns the resultant path as a Pathname. Creates
274
+ # any necessary parent directories if they do not exist.
275
+ #
276
+ # @example
277
+ # File.exist?("path/to/file") # == true
278
+ # Dir.exist?("other") # == false
279
+ # Dir.exist?("other/path") # == false
280
+ # File.exist?("other/path/file") # == false
281
+ #
282
+ # Pathname.new("path/to/file").move_into("other/path")
283
+ # # == Pathname.new("other/path/file")
284
+ #
285
+ # File.exist?("path/to/file") # == false
286
+ # Dir.exist?("other") # == true
287
+ # Dir.exist?("other/path") # == true
288
+ # File.exist?("other/path/file") # == true
139
289
  #
140
290
  # @param directory [Pathname, String]
141
291
  # @return [Pathname]
@@ -143,10 +293,121 @@ class Pathname
143
293
  self.move(directory / self.basename)
144
294
  end
145
295
 
296
+ # Copies the file or directory indicated by the Pathname to the given
297
+ # destination, and returns that destination as a Pathname. Creates
298
+ # any necessary parent directories if they do not exist. See also
299
+ # +FileUtils.cp_r+.
300
+ #
301
+ # @example
302
+ # File.exist?("path/to/file") # == true
303
+ # Dir.exist?("some") # == false
304
+ # Dir.exist?("some/other") # == false
305
+ # File.exist?("some/other/thing") # == false
306
+ #
307
+ # Pathname.new("path/to/file").copy("some/other/thing")
308
+ # # == Pathname.new("some/other/thing")
309
+ #
310
+ # File.exist?("path/to/file") # == true
311
+ # Dir.exist?("some") # == true
312
+ # Dir.exist?("some/other") # == true
313
+ # File.exist?("some/other/thing") # == true
314
+ #
315
+ # @param destination [Pathname, String]
316
+ # @return [Pathname]
317
+ def copy(destination)
318
+ destination = destination.to_pathname
319
+ destination.make_dirname
320
+ FileUtils.cp_r(self, destination)
321
+ destination
322
+ end
323
+
324
+ # Copies the file or directory indicated by the Pathname into the
325
+ # given directory, and returns the resultant path as a Pathname.
326
+ # Creates any necessary parent directories if they do not exist.
327
+ #
328
+ # @example
329
+ # File.exist?("path/to/file") # == true
330
+ # Dir.exist?("other") # == false
331
+ # Dir.exist?("other/path") # == false
332
+ # File.exist?("other/path/file") # == false
333
+ #
334
+ # Pathname.new("path/to/file").copy_into("other/path")
335
+ # # == Pathname.new("other/path/file")
336
+ #
337
+ # File.exist?("path/to/file") # == true
338
+ # Dir.exist?("other") # == true
339
+ # Dir.exist?("other/path") # == true
340
+ # File.exist?("other/path/file") # == true
341
+ #
342
+ # @param directory [Pathname, String]
343
+ # @return [Pathname]
344
+ def copy_into(directory)
345
+ self.copy(directory / self.basename)
346
+ end
347
+
348
+ # Renames the file or directory indicated by the Pathname, but
349
+ # preserves its location as indicated by +dirname+. Returns the
350
+ # resultant path as a Pathname.
351
+ #
352
+ # @example
353
+ # File.exist?("path/to/file") # == true
354
+ #
355
+ # Pathname.new("path/to/file").rename_basename("other")
356
+ # # == Pathname.new("path/to/other")
357
+ #
358
+ # File.exist?("path/to/file") # == false
359
+ # File.exist?("path/to/other") # == true
360
+ #
361
+ # @param new_basename [String]
362
+ # @return [Pathname]
363
+ def rename_basename(new_basename)
364
+ self.move(self.dirname / new_basename)
365
+ end
366
+
367
+ # Renames the file extension of the file indicated by the Pathname.
368
+ # If the file has no extension, the new extension is appended.
369
+ #
370
+ # @example replace extension
371
+ # File.exist?("path/to/file.abc") # == true
372
+ #
373
+ # Pathname.new("path/to/file.abc").rename_extname(".xyz")
374
+ # # == Pathname.new("path/to/file.xyz")
375
+ #
376
+ # File.exist?("path/to/file.abc") # == false
377
+ # File.exist?("path/to/file.xyz") # == true
378
+ #
379
+ # @example remove extension
380
+ # File.exist?("path/to/file.abc") # == true
381
+ #
382
+ # Pathname.new("path/to/file.abc").rename_extname("")
383
+ # # == Pathname.new("path/to/file")
384
+ #
385
+ # File.exist?("path/to/file.abc") # == false
386
+ # File.exist?("path/to/file") # == true
387
+ #
388
+ # @param new_extname [String]
389
+ # @return [Pathname]
390
+ def rename_extname(new_extname)
391
+ unless new_extname.start_with?(".") || new_extname.empty?
392
+ new_extname = ".#{new_extname}"
393
+ end
394
+ self.move(self.sub_ext(new_extname))
395
+ end
396
+
146
397
  # Writes given text to the file indicated by the Pathname, and returns
147
398
  # the Pathname. The file is overwritten if it already exists. Any
148
399
  # necessary parent directories are created if they do not exist.
149
400
  #
401
+ # @example
402
+ # Dir.exist?("path") # == false
403
+ # Dir.exist?("path/to") # == false
404
+ # File.exist?("path/to/file") # == false
405
+ #
406
+ # Pathname.new("path/to/file").write_text("hello world")
407
+ # # == Pathname.new("path/to/file")
408
+ #
409
+ # File.read("path/to/file") # == "hello world"
410
+ #
150
411
  # @param text [String]
151
412
  # @return [Pathname]
152
413
  def write_text(text)
@@ -158,6 +419,16 @@ class Pathname
158
419
  # returns the Pathname. The file is created if it does not exist.
159
420
  # Any necessary parent directories are created if they do not exist.
160
421
  #
422
+ # @example
423
+ # Dir.exist?("path") # == false
424
+ # Dir.exist?("path/to") # == false
425
+ # File.exist?("path/to/file") # == false
426
+ #
427
+ # Pathname.new("path/to/file").append_text("hello").append_text(" world")
428
+ # # == Pathname.new("path/to/file")
429
+ #
430
+ # File.read("path/to/file") # == "hello world"
431
+ #
161
432
  # @param text [String]
162
433
  # @return [Pathname]
163
434
  def append_text(text)
@@ -165,25 +436,40 @@ class Pathname
165
436
  self
166
437
  end
167
438
 
168
- # Writes given lines of text to the file indicated by the Pathname,
169
- # and returns the Pathname. A new line character (<code>$/</code>) is
170
- # written after each line. The file is overwritten if it already
171
- # exists. Any necessary parent directories are created if they do not
172
- # exist.
439
+ # Writes each object as a string plus a succeeding new line character
440
+ # (<code>$/</code>) to the file indicated by the Pathname. Returns
441
+ # the Pathname. The file is overwritten if it already exists. Any
442
+ # necessary parent directories are created if they do not exist.
173
443
  #
174
- # @param lines [Array<String>]
444
+ # @example
445
+ # File.exist?("path/to/file") # false
446
+ #
447
+ # Pathname.new("path/to/file").write_lines([:one, :two])
448
+ # # == Pathname.new("path/to/file")
449
+ #
450
+ # File.read("path/to/file") # == "one\ntwo\n"
451
+ #
452
+ # @param lines [Enumerable<#to_s>]
175
453
  # @return [Pathname]
176
454
  def write_lines(lines)
177
455
  self.make_dirname.open('w'){|f| f.write_lines(lines) }
178
456
  self
179
457
  end
180
458
 
181
- # Appends given lines of text to the file indicated by the Pathname,
182
- # and returns the Pathname. A new line character (<code>$/</code>) is
183
- # written after each line. The file is created if it does not exist.
184
- # Any necessary parent directories are created if they do not exist.
459
+ # Appends each object as a string plus a succeeding new line character
460
+ # (<code>$/</code>) to the file indicated by the Pathname. Returns
461
+ # the Pathname. The file is created if it does not exist. Any
462
+ # necessary parent directories are created if they do not exist.
185
463
  #
186
- # @param lines [Array<String>]
464
+ # @example
465
+ # File.exist?("path/to/file") # false
466
+ #
467
+ # Pathname.new("path/to/file").append_lines([:one, :two]).append_lines([:three, :four])
468
+ # # == Pathname.new("path/to/file")
469
+ #
470
+ # File.read("path/to/file") # == "one\ntwo\nthree\nfour\n"
471
+ #
472
+ # @param lines [Enumerable<#to_s>]
187
473
  # @return [Pathname]
188
474
  def append_lines(lines)
189
475
  self.make_dirname.open('a'){|f| f.write_lines(lines) }
@@ -198,11 +484,16 @@ class Pathname
198
484
  # Reads from the file indicated by the Pathname all lines, and returns
199
485
  # them as an array, end-of-line characters excluded. The
200
486
  # <code>$/</code> global string specifies what end-of-line characters
201
- # to look for. See also +IO#read_lines+.
487
+ # to look for. See also {IO#read_lines}.
202
488
  #
203
489
  # (Not to be confused with +Pathname#readlines+ which retains
204
490
  # end-of-line characters in every string it returns.)
205
491
  #
492
+ # @example
493
+ # File.read("path/to/file") # == "one\ntwo\n"
494
+ #
495
+ # Pathname.new("path/to/file").read_lines # == ["one", "two"]
496
+ #
206
497
  # @return [Array<String>]
207
498
  def read_lines
208
499
  self.open('r'){|f| f.read_lines }
@@ -212,14 +503,18 @@ class Pathname
212
503
  # as a string, and yields the string to the given block for editing.
213
504
  # Writes the return value of the block back to the file, overwriting
214
505
  # previous contents. Returns the file's new contents. See also
215
- # +File.edit_text+.
506
+ # {File.edit_text}.
507
+ #
508
+ # @example update JSON data file
509
+ # File.read("data.json") # == '{"nested":{"key":"value"}}'
216
510
  #
217
- # @example Update YAML data file
218
- # path.edit_text do |text|
219
- # data = YAML.load(text)
220
- # data['deeply']['nested']['key'] = 'new value'
221
- # data.to_yaml
222
- # end
511
+ # Pathname.new("data.json").edit_text do |text|
512
+ # data = JSON.parse(text)
513
+ # data["nested"]["key"] = "new value"
514
+ # data.to_json
515
+ # end # == '{"nested":{"key":"new value"}}'
516
+ #
517
+ # File.read("data.json") # == '{"nested":{"key":"new value"}}'
223
518
  #
224
519
  # @yield [text] edits current file contents
225
520
  # @yieldparam text [String] current contents
@@ -235,10 +530,15 @@ class Pathname
235
530
  # overwriting previous contents. The <code>$/</code> global string
236
531
  # specifies what end-of-line characters to use for both reading and
237
532
  # writing. Returns the array of lines that comprises the file's new
238
- # contents. See also +File.edit_lines+.
533
+ # contents. See also {File.edit_lines}.
534
+ #
535
+ # @example dedup lines of file
536
+ # File.read("entries.txt") # == "AAA\nBBB\nBBB\nCCC\nAAA\n"
239
537
  #
240
- # @example Dedup lines of file
241
- # path.edit_lines(&:uniq)
538
+ # Pathname.new("entries.txt").edit_lines(&:uniq)
539
+ # # == ["AAA", "BBB", "CCC"]
540
+ #
541
+ # File.read("entries.txt") # == "AAA\nBBB\nCCC\n"
242
542
  #
243
543
  # @yield [lines] edits current file contents
244
544
  # @yieldparam lines [Array<String>] current contents
@@ -251,6 +551,15 @@ class Pathname
251
551
  # Appends the contents of another file to the destination indicated by
252
552
  # Pathname. Returns the destination Pathname.
253
553
  #
554
+ # @example
555
+ # File.read("yearly.log") # == "one\ntwo\n"
556
+ # File.read("daily.log") # == "three\nfour\n"
557
+ #
558
+ # Pathname.new("yearly.log").append_file("daily.log")
559
+ # # == Pathname.new("yearly.log")
560
+ #
561
+ # File.read("yearly.log") # == "one\ntwo\nthree\nfour\n"
562
+ #
254
563
  # @param source [String, Pathname]
255
564
  # @return [Pathname]
256
565
  def append_file(source)
@@ -2,12 +2,15 @@ class String
2
2
 
3
3
  # Converts the string to a +Pathname+ object.
4
4
  #
5
+ # @example
6
+ # "path/to/file".to_pathname # == Pathname.new("path/to/file")
7
+ #
5
8
  # @return [Pathname]
6
9
  def to_pathname
7
10
  Pathname.new(self)
8
11
  end
9
12
 
10
- # Alias of +String#to_pathname+.
13
+ # Alias of {String#to_pathname}.
11
14
  #
12
15
  # @return [Pathname]
13
16
  alias :path :to_pathname
@@ -16,7 +19,7 @@ class String
16
19
  # +File.join+) and returns the result as a +Pathname+ object.
17
20
  #
18
21
  # @example
19
- # ("path/to" / "file").to_s #=> "path/to/file"
22
+ # "path/to" / "file" # == Pathname.new("path/to/file")
20
23
  #
21
24
  # @param child [String]
22
25
  # @return [Pathname]
@@ -28,10 +31,10 @@ class String
28
31
  # path with the argument, and returns the result as a +Pathname+
29
32
  # object. The mnenomic for this operator is that the resultant path
30
33
  # goes up one directory level from the original, then goes down to the
31
- # directory specified by the argument. See also +Pathname#^+.
34
+ # directory specified by the argument. See also {Pathname#^}.
32
35
  #
33
36
  # @example
34
- # ("path/to/file1" ^ "file2").to_s #=> "path/to/file2"
37
+ # "path/to/file1" ^ "file2" # == Pathname.new("path/to/file2")
35
38
  #
36
39
  # @param sibling [Pathname, String]
37
40
  # @return [Pathname]
@@ -43,6 +46,9 @@ class String
43
46
  # into matching paths as +Pathname+ objects. See also +Dir.glob+ and
44
47
  # +Pathname.glob+.
45
48
  #
49
+ # @example
50
+ # "*.txt".glob # == Pathname.glob("*.txt")
51
+ #
46
52
  # @return [Array<Pathname>]
47
53
  def glob
48
54
  Pathname.glob(self)
@@ -52,6 +58,10 @@ class String
52
58
  # file is overwritten if it already exists. Any necessary parent
53
59
  # directories are created if they do not exist.
54
60
  #
61
+ # @example
62
+ # "hello world".write_to_file("out.txt") # == "hello world"
63
+ # File.read("out.txt") # == "hello world"
64
+ #
55
65
  # @param file [String, Pathname]
56
66
  # @return [String]
57
67
  def write_to_file(file)
@@ -63,6 +73,12 @@ class String
63
73
  # file is created if it does not exist. Any necessary parent
64
74
  # directories are created if they do not exist.
65
75
  #
76
+ # @example
77
+ # "hello".append_to_file("out.txt") # == "hello"
78
+ # File.read("out.txt") # == "hello"
79
+ # " world".append_to_file("out.txt") # == " world"
80
+ # File.read("out.txt") # == "hello world"
81
+ #
66
82
  # @param file [String, Pathname]
67
83
  # @return [String]
68
84
  def append_to_file(file)
@@ -1,3 +1,3 @@
1
1
  module PleasantPath
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -0,0 +1,22 @@
1
+ class Object
2
+
3
+ # Dumps the Object as YAML, and writes the YAML to the specified file.
4
+ # Returns the Object unmodified.
5
+ #
6
+ # For information about available options see
7
+ # {https://ruby-doc.org/stdlib/libdoc/psych/rdoc/Psych.html#method-c-dump
8
+ # +YAML.dump+}.
9
+ #
10
+ # @example
11
+ # { "key" => "value" }.write_to_yaml("out.yaml") # == { "key" => "value" }
12
+ # File.read("out.yaml") # == "---\nkey: value\n"
13
+ #
14
+ # @param file [String, Pathname]
15
+ # @param options [Hash]
16
+ # @return [self]
17
+ def write_to_yaml(file, options = {})
18
+ File.open(file, 'w'){|f| YAML.dump(self, f, options) }
19
+ self
20
+ end
21
+
22
+ end
@@ -0,0 +1,36 @@
1
+ class Pathname
2
+
3
+ # Reads the contents of the file indicated by the Pathname, and parses
4
+ # it as YAML. The returned result will be a basic Ruby data
5
+ # structure, namely, one of: +nil+, +true+, +false+, a +Numeric+, a
6
+ # +String+, an +Array+, or a +Hash+.
7
+ #
8
+ # @example
9
+ # File.write("in.yaml", "key: value")
10
+ #
11
+ # Pathname.new("in.yaml").read_yaml # == { "key" => "value" }
12
+ #
13
+ # @return [nil, true, false, Numeric, String, Array, Hash]
14
+ def read_yaml
15
+ self.open('r'){|f| YAML.safe_load(f, [], [], false, self) }
16
+ end
17
+
18
+ # Reads the contents of the file indicated by the Pathname, and parses
19
+ # it as YAML. The parser will use type information embedded in the
20
+ # YAML to deserialize custom types. This is *UNSAFE* for YAML from
21
+ # an untrusted source. To consume untrusted YAML, use
22
+ # {Pathname#read_yaml} instead.
23
+ #
24
+ # @example
25
+ # Point = Struct.new(:x, :y)
26
+ # point = Point.new(10, 20)
27
+ # File.write("in.yaml", point.to_yaml)
28
+ #
29
+ # Pathname.new("in.yaml").load_yaml # == Point.new(10, 20)
30
+ #
31
+ # @return deserialized object
32
+ def load_yaml
33
+ YAML.load_file(self)
34
+ end
35
+
36
+ end
@@ -0,0 +1,4 @@
1
+ require "yaml"
2
+ require "pleasant_path"
3
+ require_relative "yaml/object"
4
+ require_relative "yaml/pathname"
data/lib/pleasant_path.rb CHANGED
@@ -1,7 +1,7 @@
1
- require 'pathname'
2
- require 'pleasant_path/version'
3
- require 'pleasant_path/array'
4
- require 'pleasant_path/file'
5
- require 'pleasant_path/io'
6
- require 'pleasant_path/pathname'
7
- require 'pleasant_path/string'
1
+ require "pathname"
2
+ require_relative "pleasant_path/version"
3
+ require_relative "pleasant_path/array"
4
+ require_relative "pleasant_path/file"
5
+ require_relative "pleasant_path/io"
6
+ require_relative "pleasant_path/pathname"
7
+ require_relative "pleasant_path/string"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pleasant_path
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Hefner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-04 00:00:00.000000000 Z
11
+ date: 2017-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -83,9 +83,15 @@ files:
83
83
  - lib/pleasant_path/array.rb
84
84
  - lib/pleasant_path/file.rb
85
85
  - lib/pleasant_path/io.rb
86
+ - lib/pleasant_path/json.rb
87
+ - lib/pleasant_path/json/object.rb
88
+ - lib/pleasant_path/json/pathname.rb
86
89
  - lib/pleasant_path/pathname.rb
87
90
  - lib/pleasant_path/string.rb
88
91
  - lib/pleasant_path/version.rb
92
+ - lib/pleasant_path/yaml.rb
93
+ - lib/pleasant_path/yaml/object.rb
94
+ - lib/pleasant_path/yaml/pathname.rb
89
95
  - pleasant_path.gemspec
90
96
  homepage: https://github.com/jonathanhefner/pleasant_path
91
97
  licenses:
@@ -107,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
113
  version: '0'
108
114
  requirements: []
109
115
  rubyforge_project:
110
- rubygems_version: 2.4.8
116
+ rubygems_version: 2.6.13
111
117
  signing_key:
112
118
  specification_version: 4
113
119
  summary: A fluent API for pleasant file IO.