epath 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Path - Enhanced Pathname
1
+ # Path - a Path manipulation library
2
2
 
3
3
  Path is a library to manage paths.
4
4
  It is similar to Pathname, but has some extra goodness.
@@ -9,6 +9,11 @@ Paths are naturally the subject of their methods and even if they are simple Str
9
9
 
10
10
  Also, using a path library like this avoid to remember in which class the functionality is implemented, everything is in one place (if not, please open an issue!).
11
11
 
12
+ ## Links
13
+
14
+ * [GitHub](https://github.com/eregon/epath)
15
+ * [YARD Documentation](http://rubydoc.info/github/eregon/epath/master/file/README.md)
16
+
12
17
  ## API
13
18
 
14
19
  All the useful methods of `File` (and so `IO`) and `Dir` should be included.
@@ -26,10 +31,10 @@ Path.new('/usr', 'bin')
26
31
  ```
27
32
 
28
33
  ``` ruby
29
- Path.here # == Path(__FILE__).expand
30
- Path.dir # == Path(File.dirname(__FILE__)).expand
34
+ Path.file # == Path(__FILE__).expand
35
+ Path.dir # == Path(File.dirname(__FILE__)).expand
31
36
  Path.relative(path) # == Path(File.expand_path("../#{path}", __FILE__))
32
- Path.home # == Path(File.expand_path('~'))
37
+ Path.home # == Path(File.expand_path('~'))
33
38
  ```
34
39
 
35
40
  ### temporary
@@ -41,24 +46,55 @@ Path.tmpdir
41
46
 
42
47
  ### aliases
43
48
 
44
- * expand => expand_path
45
- * relative_to => relative_path_from
49
+ * expand => expand\_path
50
+ * relative\_to => relative\_path\_from
46
51
 
47
52
  ### parts
48
53
 
49
- * base: basename(extname)
50
- * dir: alias of dirname
51
- * ext: extname without the leading dot
52
- * /: join paths
54
+ Path can split a path in two ways:
55
+
56
+ The first way is the one done by File methods (dirname, basename, extname).
57
+
58
+ The second is Path's own way in which the base is given without the extension and the extension is given without the leading dot.
59
+ The rationale behind this is to have a true three-components path, splitting on the / and the . (See [this issue](https://github.com/eregon/epath/pull/8#issuecomment-3499030) for details)
60
+
61
+ dirname basename
62
+ ____________ ______
63
+ / \ / \
64
+ /some/path/dir/file.ext
65
+ \____________/ \__/ \_/
66
+ dir base ext
67
+
68
+ path = dirname / basename
69
+ path = dirname / basename(extname) extname
70
+ path = dir / base [. ext]
71
+
72
+ * dirname: "/some/path/dir"
73
+ * basename: "file.ext"
74
+ * extname: ".ext"
75
+
76
+ <!-- -->
77
+
78
+ * dir: alias of dirname: "/some/paths/dir"
79
+ * base: basename(extname), the basename without the extension: "file"
80
+ * ext: extname without the leading dot: "ext"
81
+
82
+ <!-- -->
83
+
84
+ ### join
85
+
86
+ * join(*parts)
87
+ * /: join paths (as Pathname#+)
53
88
 
54
89
  ```ruby
55
90
  Path('/usr')/'bin'
56
91
  ```
57
92
 
58
- These method names are too long, any idea to make them shorter and clear?
93
+ ### extensions
59
94
 
60
- * without_extension
61
- * replace_extension(new_ext)
95
+ * add\_ext / add\_extension
96
+ * rm\_ext / without\_extension
97
+ * sub\_ext(new\_ext) / replace\_extension(new\_ext)
62
98
 
63
99
  ### glob
64
100
 
@@ -67,13 +103,15 @@ These method names are too long, any idea to make them shorter and clear?
67
103
 
68
104
  ### structure
69
105
 
70
- * ancestors: self and all the parent directories
106
+ * ascend, ancestors: self and all the parent directories
107
+ * descend: in the reverse order
71
108
  * backfind: ascends the parents until it finds the given path
72
109
 
73
110
  ``` ruby
74
111
  # Path.backfind is Path.here.backfind
75
112
  Path.backfind('lib') # => Path's lib folder
76
- # it accepts XPath-like context
113
+
114
+ # It accepts XPath-like context
77
115
  Path.backfind('.[.git]') # => the root of this repository
78
116
  ```
79
117
 
@@ -86,12 +124,12 @@ Path.backfind('.[.git]') # => the root of this repository
86
124
  ### management
87
125
 
88
126
  * mkdir
89
- * mkdir_p
90
- * rm_rf
127
+ * mkdir\_p
128
+ * rm\_rf
91
129
 
92
- ### Incompatibilities with Pathname
130
+ ### require
93
131
 
94
- * #entries never returns . and ..
132
+ * Path.require\_tree: require all .rb files recursively (in alphabetic order)
95
133
 
96
134
  ## Status
97
135
 
@@ -101,6 +139,7 @@ This is still in the early development stage, you should expect many additions a
101
139
 
102
140
  Benoit Daloze - eregon
103
141
 
104
- ### Contributors
142
+ ## Contributors
105
143
 
106
- Bernard Lambeau - blambeau
144
+ Bernard Lambeau - blambeau
145
+ Ravil Bayramgalin - brainopia
@@ -5,5 +5,7 @@ Gem::Specification.new do |s|
5
5
  s.email = 'eregontp@gmail.com'
6
6
  s.homepage = 'https://github.com/eregon/epath'
7
7
  s.files = Dir['lib/**/*.rb'] + %w[README.md LICENSE epath.gemspec]
8
- s.version = '0.0.1'
8
+ s.version = '0.1.0'
9
+
10
+ s.add_development_dependency 'rspec'
9
11
  end
@@ -1,34 +1,20 @@
1
- # Enchanced Pathname
2
- # Use the composite pattern with a Pathname
1
+ # Path - a Path manipulation library
2
+
3
+ Dir.glob(File.expand_path('../epath/*.rb',__FILE__)) { |file| require file }
3
4
 
4
- require File.expand_path('../epath/implementation', __FILE__)
5
5
  require 'tempfile'
6
6
 
7
7
  class Path
8
- DOTS = %w[. ..]
9
-
10
8
  class << self
11
- def new(*args)
12
- if args.size == 1 and Path === args[0]
13
- args[0]
14
- else
15
- super(*args)
16
- end
17
- end
18
- alias_method :[], :new
19
-
20
- def to_proc
21
- lambda { |path| new(path) }
22
- end
23
-
24
- def here(from = nil)
25
- from ||= caller
26
- new(from.first.split(/:\d+(?:$|:in)/).first).expand
9
+ def file(from = nil)
10
+ from ||= caller # this can not be moved as a default argument, JRuby optimizes it
11
+ # v This : is there to define a group without capturing
12
+ new(from.first.rpartition(/:\d+(?:$|:in )/).first).expand
27
13
  end
28
- alias_method :file, :here
14
+ alias :here :file
29
15
 
30
16
  def dir(from = nil)
31
- from ||= caller
17
+ from ||= caller # this can not be moved as a default argument, JRuby optimizes it
32
18
  file(from).dir
33
19
  end
34
20
 
@@ -41,7 +27,7 @@ class Path
41
27
  end
42
28
 
43
29
  def backfind(path)
44
- here(caller).backfind(path)
30
+ file(caller).backfind(path)
45
31
  end
46
32
 
47
33
  def tmpfile(basename = '', tmpdir = nil, options = nil)
@@ -57,7 +43,7 @@ class Path
57
43
  end
58
44
  file
59
45
  end
60
- alias_method :tempfile, :tmpfile
46
+ alias :tempfile :tmpfile
61
47
 
62
48
  def tmpdir(prefix_suffix = nil, *rest)
63
49
  require 'tmpdir'
@@ -71,108 +57,27 @@ class Path
71
57
  end
72
58
  dir
73
59
  end
74
- end
75
-
76
- def initialize(*parts)
77
- path = parts.size > 1 ? parts.join(File::SEPARATOR) : parts.first
78
- if Tempfile === path
79
- @_tmpfile = path # We would not want it to be GC'd
80
- @path = path.path
81
- elsif String === path
82
- @path = path.dup
83
- else
84
- @path = path.to_s
85
- end
86
- taint if @path.tainted?
87
- end
88
-
89
- def / part
90
- join part.to_s
91
- end
92
-
93
- def base # basename(extname)
94
- basename(extname)
95
- end
96
-
97
- def ext # extname without leading .
98
- ext = extname
99
- ext.empty? ? ext : ext[1..-1]
100
- end
101
-
102
- def without_extension # rm_ext
103
- dir / base
104
- end
105
-
106
- # NOTE: Pathname has a similar feature named sub_ext
107
- # It might be a better method name
108
- def replace_extension(ext)
109
- ext = ".#{ext}" unless ext.start_with? '.'
110
- Path.new(without_extension.to_s + ext)
111
- end
112
60
 
113
- def entries
114
- (Dir.entries(@path) - DOTS).map { |entry| Path.new(@path, entry).cleanpath }
115
- end
116
-
117
- def glob(pattern, flags = 0)
118
- Dir.glob(join(pattern), flags).map(&Path)
119
- end
120
-
121
- def rm
122
- FileUtils.rm(@path)
123
- self
124
- end
125
-
126
- def rm_f
127
- FileUtils.rm_f(@path)
128
- self
129
- end
130
-
131
- def rm_rf
132
- FileUtils.rm_rf(@path)
133
- self
134
- end
135
-
136
- def mkdir_p
137
- FileUtils.mkdir_p(@path)
138
- self
139
- end
140
-
141
- def write(contents, open_args = nil)
142
- if IO.respond_to? :write
143
- IO.write(@path, contents, *[open_args].compact)
144
- else
145
- open('w', *[open_args].compact) { |f| f.write(contents) }
61
+ def tmpchdir(prefix_suffix = nil, *rest)
62
+ tmpdir do |dir|
63
+ dir.chdir do
64
+ yield dir
65
+ end
66
+ end
146
67
  end
147
68
  end
148
69
 
149
- def append(contents, open_args = nil)
150
- if IO.respond_to? :write
151
- open_args = (Array(open_args) << {:mode => 'a'})
152
- IO.write(@path, contents, *open_args.compact)
153
- else
154
- open('a', *[open_args].compact) { |f| f.write(contents) }
155
- end
156
- end
70
+ alias :/ :+
157
71
 
158
- def to_sym
159
- to_s.to_sym
160
- end
72
+ alias :relative_to :relative_path_from
73
+ alias :% :relative_path_from
161
74
 
162
- def relative_to other
163
- relative_path_from Path.new other
75
+ def inside? ancestor
76
+ @path == ancestor.to_s or @path.start_with?("#{ancestor}/")
164
77
  end
165
- alias_method :%, :relative_to
166
78
 
167
- def ancestors
168
- ancestors = lambda do |y|
169
- y << path = expand
170
- until (path = path.parent).root?
171
- y << path
172
- end
173
- y << path
174
- end
175
- RUBY_VERSION > '1.9' ? Enumerator.new(&ancestors) : ancestors.call([])
79
+ def outside? ancestor
80
+ !inside?(ancestor)
176
81
  end
177
82
 
178
83
  def backfind(path)
@@ -183,14 +88,20 @@ class Path
183
88
  result/path if result
184
89
  end
185
90
 
186
- alias_method :expand, :expand_path
187
- alias_method :dir, :dirname
188
- end
91
+ # Setup
92
+ register_loader 'yml', 'yaml' do |path|
93
+ require 'yaml'
94
+ YAML.load_file(path)
95
+ end
189
96
 
190
- EPath = Path # to meet everyone's expectations
97
+ register_loader 'json' do |path|
98
+ require 'json'
99
+ JSON.load(path.read)
100
+ end
191
101
 
192
- unless defined? NO_EPATH_GLOBAL_FUNCTION
193
- def Path(*args)
194
- Path.new(*args)
102
+ register_loader 'gemspec' do |path|
103
+ eval path.read
195
104
  end
196
105
  end
106
+
107
+ EPath = Path # to meet everyone's expectations
@@ -0,0 +1,123 @@
1
+ class Path
2
+ class << self
3
+ # Returns or yields Path objects. See +Dir.glob+.
4
+ def glob(*args) # :yield: path
5
+ if block_given?
6
+ Dir.glob(*args) { |f| yield new(f) }
7
+ else
8
+ Dir.glob(*args).map(&Path)
9
+ end
10
+ end
11
+
12
+ # Returns the current working directory as a Path. See +Dir.getwd+.
13
+ def Path.getwd
14
+ new Dir.getwd
15
+ end
16
+ alias :pwd :getwd
17
+ end
18
+
19
+ # Iterates over the entries (files and subdirectories) in the directory.
20
+ # It yields a Path object for each entry.
21
+ def each_entry(&block) # :yield: path
22
+ Dir.foreach(@path) { |f| yield Path.new(f) }
23
+ end
24
+
25
+ # Create the referenced directory and returns self. See +Dir.mkdir+.
26
+ def mkdir(*args)
27
+ Dir.mkdir(@path, *args)
28
+ self
29
+ end
30
+
31
+ # Remove the referenced directory. See +Dir.rmdir+.
32
+ def rmdir
33
+ Dir.rmdir(@path)
34
+ end
35
+
36
+ # See +Dir.open+.
37
+ def opendir(&block) # :yield: dir
38
+ Dir.open(@path, &block)
39
+ end
40
+
41
+ def glob(pattern, flags = 0)
42
+ Dir.glob(join(pattern), flags).map(&Path)
43
+ end
44
+
45
+ # [DEPRECATED] Return the entries (files and subdirectories) in the directory.
46
+ # Each Path only contains the filename.
47
+ # The result may contain the current directory #<Path .> and the parent directory #<Path ..>.
48
+ #
49
+ # Path('/usr/local').entries
50
+ # # => [#<Path share>, #<Path lib>, #<Path .>, #<Path ..>, <Path bin>, ...]
51
+ #
52
+ # This method is deprecated, since it is too low level and likely useless in Ruby.
53
+ # But it is there for the sake of compatibility with Dir.entries (and Pathname#entries)
54
+ #
55
+ # Use #children instead.
56
+ def entries
57
+ Dir.entries(@path).map(&Path)
58
+ end
59
+
60
+ def chdir(&block)
61
+ Dir.chdir(@path, &block)
62
+ end
63
+
64
+ # Returns the children of the directory (files and subdirectories, not
65
+ # recursive) as an array of Path objects. By default, the returned
66
+ # paths will have enough information to access the files. If you set
67
+ # +with_directory+ to +false+, then the returned paths will contain the
68
+ # filename only.
69
+ #
70
+ # For example:
71
+ # pn = Path("/usr/lib/ruby/1.8")
72
+ # pn.children
73
+ # # -> [ #<Path /usr/lib/ruby/1.8/English.rb>,
74
+ # #<Path /usr/lib/ruby/1.8/Env.rb>,
75
+ # #<Path /usr/lib/ruby/1.8/abbrev.rb>, ... ]
76
+ # pn.children(false)
77
+ # # -> [ #<Path English.rb>, #<Path Env.rb>, #<Path abbrev.rb>, ... ]
78
+ #
79
+ # Note that the results never contain the entries +.+ and +..+ in
80
+ # the directory because they are not children.
81
+ def children(with_directory=true)
82
+ with_directory = false if @path == '.'
83
+ result = []
84
+ Dir.foreach(@path) { |e|
85
+ next if e == '.' || e == '..'
86
+ if with_directory
87
+ result << Path.new(@path, e)
88
+ else
89
+ result << Path.new(e)
90
+ end
91
+ }
92
+ result
93
+ end
94
+
95
+ # Iterates over the children of the directory
96
+ # (files and subdirectories, not recursive).
97
+ # It yields Path object for each child.
98
+ # By default, the yielded paths will have enough information to access the files.
99
+ # If you set +with_directory+ to +false+, then the returned paths will contain the filename only.
100
+ #
101
+ # Path("/usr/local").each_child { |f| p f } # =>
102
+ # #<Path /usr/local/share>
103
+ # #<Path /usr/local/bin>
104
+ # #<Path /usr/local/games>
105
+ # #<Path /usr/local/lib>
106
+ # #<Path /usr/local/include>
107
+ # #<Path /usr/local/sbin>
108
+ # #<Path /usr/local/src>
109
+ # #<Path /usr/local/man>
110
+ #
111
+ # Path("/usr/local").each_child(false) { |f| p f } # =>
112
+ # #<Path share>
113
+ # #<Path bin>
114
+ # #<Path games>
115
+ # #<Path lib>
116
+ # #<Path include>
117
+ # #<Path sbin>
118
+ # #<Path src>
119
+ # #<Path man>
120
+ def each_child(with_directory=true, &b)
121
+ children(with_directory).each(&b)
122
+ end
123
+ end