pleasant_path 1.0.0 → 1.1.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: 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.