dle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 954b6dbb956a5a13cab35c61df14f1d614f246d2
4
+ data.tar.gz: 5e80a17b73437a40587f6be58b1d0f48d87d33bf
5
+ SHA512:
6
+ metadata.gz: 1a75351e1d3d18792ed530564364a773a8d5e7e83fe65cea779c232c6f35ad448184c93ef33f82085482bba4616962aea4283cb5d9390ca781b47d25eacbcafe
7
+ data.tar.gz: 2e13b0f57002f7e517cbbbc166cd1aec9bd41d42a7cd6960711f19a18306d495f769e1cd36f98a5a818c18fcd58659e91fe151ae8a454517fd55501c1004e041
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dle.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Sven Pachnit
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # DLE
2
+
3
+ **Directory List Edit – Edit file structures in your favorite editor!**
4
+ You can copy, move, rename, chmod, chown or remove individual files or directories with your favorite text editor.
5
+
6
+ **BETA product, use at your own risk, use `--simulate` to be sure, always have a backup!**
7
+
8
+ ## Requirements
9
+
10
+ You will need a UNIX system with a working Ruby installation, sorry Windozer!
11
+
12
+ ## Installation
13
+
14
+ Simple as:
15
+
16
+ $ gem install dle
17
+
18
+ You may also want to define your favorite editor by setting this enviromental variable (in your profile or bashrc):
19
+
20
+ export DLE_EDITOR="subl -w"
21
+
22
+ Note that you need a blocking call to the editor (for GUI editors). Sublime and Textmate both accept `-w` or `--wait`.
23
+
24
+ ## Usage
25
+
26
+ To get a list of available options invoke DLE with the `--help` or `-h` option:
27
+
28
+ Usage: dle [options] base_directory
29
+ -d, --dotfiles Include dotfiles (unix invisible)
30
+ -r, --skip-review Skip review changes before applying
31
+ -s, --simulate Don't apply changes, show commands instead
32
+ -f, --file DLFILE Use input file (be careful)
33
+ -m, --monochrome Don't colorize output
34
+ -h, --help Shows this help
35
+ -v, --version Shows version and other info
36
+ -z Do not check for updates on GitHub (with -v/--version)
37
+
38
+ Change into a directory you want to work with and invoke DLE:
39
+
40
+ dle .
41
+ dle ~/some_path
42
+
43
+ Your editor will open with a list of your directory structure which you can edit accordingly to these rules:
44
+
45
+ * If you remove a line we just don't care!
46
+ * If you add a line we just don't care!
47
+ * If you change a path we will "mkdir -p" the destination and move the file/dir
48
+ * If you change the owner we will "chown" the file/dir
49
+ * If you change the mode we will "chmod" the file/dir
50
+ * If you change the mode to "cp" and modify the path we will copy instead of moving/renaming
51
+ * If you change the mode to "del" we will "rm" the file
52
+ * If you change the mode to "delr" we will "rm" the file or directory
53
+ * If you change the mode to "delf" or "delrf" we will "rm -f" the file or directory
54
+ * We will apply changes in this order (inside-out):
55
+ * Ownership
56
+ * Permissions
57
+ * Rename/Move
58
+ * Copy
59
+ * Delete
60
+
61
+ ## Caveats
62
+
63
+ DLE relies on inode values, do not use with hardlinks! This may lead to unexpected file operations or data loss!
64
+
65
+ ## Contributing
66
+
67
+ 1. Fork it ( http://github.com/2called-chaos/dle/fork )
68
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
69
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
70
+ 4. Push to the branch (`git push origin my-new-feature`)
71
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/dle ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require "dle"
3
+ Dle::Application.dispatch(ENV, ARGV)
data/bin/dle.sh ADDED
@@ -0,0 +1,14 @@
1
+ #!/bin/bash
2
+
3
+ # That's __FILE__ in BASH :)
4
+ # From: http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in
5
+ SOURCE="${BASH_SOURCE[0]}"
6
+ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
7
+ MCLDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
8
+ SOURCE="$(readlink "$SOURCE")"
9
+ [[ $SOURCE != /* ]] && SOURCE="$MCLDIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
10
+ done
11
+ PROJECT_ROOT="$( cd -P "$( dirname "$SOURCE" )"/.. && pwd )"
12
+
13
+ # Actually run script
14
+ cd $PROJECT_ROOT && bundle exec ruby bin/dle "$@"
data/dle.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dle/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dle"
8
+ spec.version = Dle::VERSION
9
+ spec.authors = ["Sven Pachnit"]
10
+ spec.email = ["sven@bmonkeys.net"]
11
+ spec.summary = %q{Directory List Edit – Edit file structures in your favorite editor!}
12
+ spec.description = %q{You can move, rename, chmod, chown or remove individual files or directories with your favorite text editor.}
13
+ spec.homepage = "https://github.com/2called-chaos/dle"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "pry"
22
+ spec.add_development_dependency "bundler", "~> 1.5"
23
+ spec.add_development_dependency "rake"
24
+ end
@@ -0,0 +1,112 @@
1
+ # encoding: utf-8
2
+
3
+ class Object
4
+ # An object is blank if it's false, empty, or a whitespace string.
5
+ # For example, '', ' ', +nil+, [], and {} are all blank.
6
+ #
7
+ # This simplifies:
8
+ #
9
+ # if address.nil? || address.empty?
10
+ #
11
+ # ...to:
12
+ #
13
+ # if address.blank?
14
+ def blank?
15
+ respond_to?(:empty?) ? empty? : !self
16
+ end
17
+
18
+ # An object is present if it's not <tt>blank?</tt>.
19
+ def present?
20
+ !blank?
21
+ end
22
+
23
+ # Returns object if it's <tt>present?</tt> otherwise returns +nil+.
24
+ # <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
25
+ #
26
+ # This is handy for any representation of objects where blank is the same
27
+ # as not present at all. For example, this simplifies a common check for
28
+ # HTTP POST/query parameters:
29
+ #
30
+ # state = params[:state] if params[:state].present?
31
+ # country = params[:country] if params[:country].present?
32
+ # region = state || country || 'US'
33
+ #
34
+ # ...becomes:
35
+ #
36
+ # region = params[:state].presence || params[:country].presence || 'US'
37
+ def presence
38
+ self if present?
39
+ end
40
+ end
41
+
42
+ class NilClass
43
+ # +nil+ is blank:
44
+ #
45
+ # nil.blank? # => true
46
+ #
47
+ def blank?
48
+ true
49
+ end
50
+ end
51
+
52
+ class FalseClass
53
+ # +false+ is blank:
54
+ #
55
+ # false.blank? # => true
56
+ #
57
+ def blank?
58
+ true
59
+ end
60
+ end
61
+
62
+ class TrueClass
63
+ # +true+ is not blank:
64
+ #
65
+ # true.blank? # => false
66
+ #
67
+ def blank?
68
+ false
69
+ end
70
+ end
71
+
72
+ class Array
73
+ # An array is blank if it's empty:
74
+ #
75
+ # [].blank? # => true
76
+ # [1,2,3].blank? # => false
77
+ #
78
+ alias_method :blank?, :empty?
79
+ end
80
+
81
+ class Hash
82
+ # A hash is blank if it's empty:
83
+ #
84
+ # {}.blank? # => true
85
+ # {:key => 'value'}.blank? # => false
86
+ #
87
+ alias_method :blank?, :empty?
88
+ end
89
+
90
+ class String
91
+ # A string is blank if it's empty or contains whitespaces only:
92
+ #
93
+ # ''.blank? # => true
94
+ # ' '.blank? # => true
95
+ # ' '.blank? # => true
96
+ # ' something here '.blank? # => false
97
+ #
98
+ def blank?
99
+ self !~ /[^[:space:]]/
100
+ end
101
+ end
102
+
103
+ class Numeric #:nodoc:
104
+ # No number is blank:
105
+ #
106
+ # 1.blank? # => false
107
+ # 0.blank? # => false
108
+ #
109
+ def blank?
110
+ false
111
+ end
112
+ end
@@ -0,0 +1,53 @@
1
+ class Object
2
+ # Invokes the public method identified by the symbol +method+, passing it any arguments
3
+ # and/or the block specified, just like the regular Ruby <tt>Object#public_send</tt> does.
4
+ #
5
+ # *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
6
+ # and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
7
+ #
8
+ # If try is called without a method to call, it will yield any given block with the object.
9
+ #
10
+ # ==== Examples
11
+ #
12
+ # Without +try+
13
+ # @person && @person.name
14
+ # or
15
+ # @person ? @person.name : nil
16
+ #
17
+ # With +try+
18
+ # @person.try(:name)
19
+ #
20
+ # +try+ also accepts arguments and/or a block, for the method it is trying
21
+ # Person.try(:find, 1)
22
+ # @people.try(:collect) {|p| p.name}
23
+ #
24
+ # Without a method argument try will yield to the block unless the receiver is nil.
25
+ # @person.try { |p| "#{p.first_name} #{p.last_name}" }
26
+ #--
27
+ # +try+ behaves like +Object#public_send+, unless called on +NilClass+.
28
+ def try(*a, &b)
29
+ if a.empty? && block_given?
30
+ yield self
31
+ else
32
+ public_send(*a, &b)
33
+ end
34
+ end
35
+ end
36
+
37
+ class NilClass
38
+ # Calling +try+ on +nil+ always returns +nil+.
39
+ # It becomes specially helpful when navigating through associations that may return +nil+.
40
+ #
41
+ # === Examples
42
+ #
43
+ # nil.try(:name) # => nil
44
+ #
45
+ # Without +try+
46
+ # @person && !@person.children.blank? && @person.children.first.name
47
+ #
48
+ # With +try+
49
+ # @person.try(:children).try(:first).try(:name)
50
+ def try(*args)
51
+ nil
52
+ end
53
+ end
@@ -0,0 +1,258 @@
1
+ module Banana
2
+ # This class provides a simple logger which maintains and displays the runtime of the logger instance.
3
+ # It is intended to be used with the colorize gem but it brings its own colorization to eliminate a
4
+ # dependency. You should initialize the logger as soon as possible to get an accurate runtime.
5
+ #
6
+ # @example
7
+ # logger = Banana::Logger.new
8
+ # logger.log "foo"
9
+ # logger.prefix = "[a] "
10
+ # logger.debug "bar"
11
+ # sleep 2
12
+ # logger.ensure_prefix("[b] ") { logger.warn "baz" }
13
+ # logger.log("rab!", :abort)
14
+ #
15
+ # # Result:
16
+ # # [00:00:00.000 INFO] foo
17
+ # # [00:00:00.000 DEBUG] [a] bar
18
+ # # [00:00:02.001 WARN] [b] baz
19
+ # # [00:00:02.001 ABORT] [a] rab!
20
+ #
21
+ # @!attribute [r] startup
22
+ # @return [DateTime] Point of time where the logger was initiated.
23
+ # @!attribute [r] channel
24
+ # @return [Object] The object where messages are getting send to.
25
+ # @!attribute [r] method
26
+ # @return [Object] The method used to send messages to {#channel}.
27
+ # @!attribute [r] logged
28
+ # @return [Integer] Amount of messages send to channel.
29
+ # @note This counter starts from 0 in every {#ensure_method} or {#log_with_print} block but gets
30
+ # added to the main counter after the call.
31
+ # @!attribute timestr
32
+ # @return [Boolean] Set to false if the runtime indicator should not be printed (default: true).
33
+ # @!attribute colorize
34
+ # @return [Boolean] Set to false if output should not be colored (default: true).
35
+ # @!attribute prefix
36
+ # @return [String] Current prefix string for logged messages.
37
+ class Logger
38
+ attr_reader :startup, :channel, :method, :logged
39
+ attr_accessor :colorize, :prefix
40
+
41
+ # Foreground color values
42
+ COLORMAP = {
43
+ black: 30,
44
+ red: 31,
45
+ green: 32,
46
+ yellow: 33,
47
+ blue: 34,
48
+ magenta: 35,
49
+ cyan: 36,
50
+ white: 37,
51
+ }
52
+
53
+ # Initializes a new logger instance. The internal runtime measurement starts here!
54
+ #
55
+ # There are 4 default log levels: info (yellow), warn & abort (red) and debug (blue).
56
+ # All are enabled by default. You propably want to {#disable disable(:debug)}.
57
+ #
58
+ # @param scope Only for backward compatibility, not used
59
+ # @todo add option hash
60
+ def initialize scope = nil
61
+ @startup = Time.now.utc
62
+ @colorize = true
63
+ @prefix = ""
64
+ @enabled = true
65
+ @timestr = true
66
+ @channel = ::Kernel
67
+ @method = :puts
68
+ @logged = 0
69
+ @levels = {
70
+ info: { color: "yellow", enabled: true },
71
+ warn: { color: "red", enabled: true },
72
+ abort: { color: "red", enabled: true },
73
+ debug: { color: "blue", enabled: true },
74
+ }
75
+ end
76
+
77
+ # The default channel is `Kernel` which is Ruby's normal `puts`.
78
+ # Attach it to a open file with write access and it will write into
79
+ # the file. Ensure to close the file in your code.
80
+ #
81
+ # @param channel Object which responds to puts and print
82
+ def attach channel
83
+ @channel = channel
84
+ end
85
+
86
+ # Print raw message onto {#channel} using {#method}.
87
+ #
88
+ # @param [String] msg Message to send to {#channel}.
89
+ # @param [Symbol] method Override {#method}.
90
+ def raw msg, method = @method
91
+ @channel.send(method, msg)
92
+ end
93
+
94
+ # Add additional log levels which are automatically enabled.
95
+ # @param [Hash] levels Log levels in the format `{ debug: "red" }`
96
+ def log_level levels = {}
97
+ levels.each do |level, color|
98
+ @levels[level.to_sym] ||= { enabled: true }
99
+ @levels[level.to_sym][:color] = color
100
+ end
101
+ end
102
+
103
+ # Calls the block with the given prefix and ensures that the prefix
104
+ # will be the same as before.
105
+ #
106
+ # @param [String] prefix Prefix to use for the block
107
+ # @param [Proc] block Block to call
108
+ def ensure_prefix prefix, &block
109
+ old_prefix, @prefix = @prefix, prefix
110
+ block.call
111
+ ensure
112
+ @prefix = old_prefix
113
+ end
114
+
115
+ # Calls the block after changing the output method.
116
+ # It also ensures to set back the method to what it was before.
117
+ #
118
+ # @param [Symbol] method Method to call on {#channel}
119
+ def ensure_method method, &block
120
+ old_method, old_logged = @method, @logged
121
+ @method, @logged = method, 0
122
+ block.call
123
+ ensure
124
+ @method = old_method
125
+ @logged += old_logged
126
+ end
127
+
128
+ # Calls the block after changing the output method to `:print`.
129
+ # It also ensures to set back the method to what it was before.
130
+ #
131
+ # @param [Boolean] clear If set to true and any message was printed inside the block
132
+ # a \n newline character will be printed.
133
+ def log_with_print clear = true, &block
134
+ ensure_method :print do
135
+ begin
136
+ block.call
137
+ ensure
138
+ puts if clear && @logged > 0
139
+ end
140
+ end
141
+ end
142
+
143
+ # Calls the block after disabling the runtime indicator.
144
+ # It also ensures to set back the old setting after execution.
145
+ def log_without_timestr &block
146
+ timestr, @timestr = @timestr, false
147
+ block.call
148
+ ensure
149
+ @timestr = timestr
150
+ end
151
+
152
+ # @return [Boolean] returns true if the log level format :debug is enabled.
153
+ def debug?
154
+ enabled? :debug
155
+ end
156
+
157
+ # If a `level` is provided it will return true if this log level is enabled.
158
+ # If no `level` is provided it will return true if the logger is enabled generally.
159
+ #
160
+ # @return [Boolean] returns true if the given log level is enabled
161
+ def enabled? level = nil
162
+ level.nil? ? @enabled : @levels[level.to_sym][:enabled]
163
+ end
164
+
165
+ # Same as {#enabled?} just negated.
166
+ def disabled? level = nil
167
+ !enabled?(level)
168
+ end
169
+
170
+ # Same as {#enable} just negated.
171
+ #
172
+ # @param [Symbol, String] level Loglevel to disable.
173
+ def disable level = nil
174
+ if level.nil?
175
+ @enabled = false
176
+ else
177
+ @levels[level.to_sym][:enabled] = false
178
+ end
179
+ end
180
+
181
+ # Enables the given `level` or the logger generally if no `level` is given.
182
+ # If the logger is disabled no messages will be printed. If it is enabled
183
+ # only messages for enabled log levels will be printed.
184
+ #
185
+ # @param [Symbol, String] level Loglevel to enable.
186
+ def enable level = nil
187
+ if level.nil?
188
+ @enabled = true
189
+ else
190
+ @levels[level.to_sym][:enabled] = true
191
+ end
192
+ end
193
+
194
+ # Colorizes the given string with the given color. It uses the build-in
195
+ # colorization feature. You may want to use the colorize gem.
196
+ #
197
+ # @param [String] str The string to colorize
198
+ # @param [Symbol, String] color The color to use (see {COLORMAP})
199
+ # @raise [ArgumentError] if color does not exist in {COLORMAP}.
200
+ def colorize str, color
201
+ ccode = COLORMAP[color.to_sym] || raise(ArgumentError, "Unknown color #{color}!")
202
+ "\e[#{ccode}m#{str}\e[0m"
203
+ end
204
+
205
+ def colorize?
206
+ @colorize
207
+ end
208
+
209
+ # This method is the only method which sends the message `msg` to `@channel` via `@method`.
210
+ # It also increments the message counter `@logged` by one.
211
+ #
212
+ # This method instantly returns nil if the logger or the given log level `type` is disabled.
213
+ #
214
+ # @param [String] msg The message to send to the channel
215
+ # @param [Symbol] type The log level
216
+ def log msg, type = :info
217
+ return if !@enabled || !@levels[type][:enabled]
218
+ if @levels[type.to_sym] || !@levels.key?(type.to_sym)
219
+ time = Time.at(Time.now.utc - @startup).utc
220
+ timestr = @timestr ? "[#{time.strftime("%H:%M:%S.%L")} #{type.to_s.upcase}]\t" : ""
221
+
222
+ if @colorize
223
+ msg = "#{colorize(timestr, @levels[type.to_sym][:color])}" <<
224
+ "#{@prefix}" <<
225
+ "#{colorize(msg, @levels[type.to_sym][:color])}"
226
+ else
227
+ msg = "#{timestr}#{@prefix}#{msg}"
228
+ end
229
+ @logged += 1
230
+ @channel.send(@method, msg)
231
+ end
232
+ end
233
+ alias_method :info, :log
234
+
235
+ # Shortcut for {#log #log(msg, :debug)}
236
+ #
237
+ # @param [String] msg The message to send to {#log}.
238
+ def debug msg
239
+ log(msg, :debug)
240
+ end
241
+
242
+ # Shortcut for {#log #log(msg, :warn)} but sets channel method to "warn".
243
+ #
244
+ # @param [String] msg The message to send to {#log}.
245
+ def warn msg
246
+ ensure_method(:warn) { log(msg, :warn) }
247
+ end
248
+
249
+ # Shortcut for {#log #log(msg, :abort)} but sets channel method to "warn".
250
+ #
251
+ # @param [String] msg The message to send to {#log}.
252
+ # @param [Integer] exit_code Exits with given code or does nothing when falsy.
253
+ def abort msg, exit_code = false
254
+ ensure_method(:warn) { log(msg, :abort) }
255
+ exit(exit_code) if exit_code
256
+ end
257
+ end
258
+ end