rubyexts 0.0.1

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.
Files changed (51) hide show
  1. data/CHANGELOG +2 -0
  2. data/LICENSE +20 -0
  3. data/README.textile +0 -0
  4. data/Rakefile +79 -0
  5. data/TODO.txt +6 -0
  6. data/lib/rubyexts.rb +102 -0
  7. data/lib/rubyexts/array.rb +20 -0
  8. data/lib/rubyexts/attribute.rb +151 -0
  9. data/lib/rubyexts/capture_io.rb +32 -0
  10. data/lib/rubyexts/class.rb +177 -0
  11. data/lib/rubyexts/colored_string.rb +103 -0
  12. data/lib/rubyexts/enumerable.rb +30 -0
  13. data/lib/rubyexts/file.rb +84 -0
  14. data/lib/rubyexts/hash.rb +180 -0
  15. data/lib/rubyexts/kernel.rb +91 -0
  16. data/lib/rubyexts/module.rb +53 -0
  17. data/lib/rubyexts/object.rb +56 -0
  18. data/lib/rubyexts/object_space.rb +16 -0
  19. data/lib/rubyexts/os.rb +89 -0
  20. data/lib/rubyexts/platform.rb +27 -0
  21. data/lib/rubyexts/random.rb +25 -0
  22. data/lib/rubyexts/string.rb +92 -0
  23. data/lib/rubyexts/time.rb +15 -0
  24. data/lib/rubyexts/time_dsl.rb +62 -0
  25. data/lib/rubyexts/try_dup.rb +43 -0
  26. data/lib/rubyexts/unique_array.rb +16 -0
  27. data/rubyexts.gemspec +36 -0
  28. data/script/spec +12 -0
  29. data/spec/rubyexts/array_spec.rb +19 -0
  30. data/spec/rubyexts/attribute_spec.rb +37 -0
  31. data/spec/rubyexts/class_spec.rb +1 -0
  32. data/spec/rubyexts/cli_spec.rb +0 -0
  33. data/spec/rubyexts/colored_string_spec.rb +9 -0
  34. data/spec/rubyexts/enumerable_spec.rb +52 -0
  35. data/spec/rubyexts/file_spec.rb +78 -0
  36. data/spec/rubyexts/hash_spec.rb +91 -0
  37. data/spec/rubyexts/kernel_spec.rb +9 -0
  38. data/spec/rubyexts/module_spec.rb +0 -0
  39. data/spec/rubyexts/object_space_spec.rb +17 -0
  40. data/spec/rubyexts/object_spec.rb +57 -0
  41. data/spec/rubyexts/os_spec.rb +121 -0
  42. data/spec/rubyexts/platform_spec.rb +0 -0
  43. data/spec/rubyexts/random_spec.rb +31 -0
  44. data/spec/rubyexts/string_spec.rb +23 -0
  45. data/spec/rubyexts/time_dsl_spec.rb +88 -0
  46. data/spec/rubyexts/time_spec.rb +11 -0
  47. data/spec/rubyexts/unique_array_spec.rb +0 -0
  48. data/spec/rubyexts_spec.rb +182 -0
  49. data/spec/spec.opts +5 -0
  50. data/spec/spec_helper.rb +16 -0
  51. metadata +104 -0
@@ -0,0 +1,103 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "string"
4
+ require_relative "attribute"
5
+
6
+ class ColoredString
7
+ ATTRIBUTES = {
8
+ clear: 0,
9
+ reset: 0, # synonym for :clear
10
+ bold: 1,
11
+ dark: 2,
12
+ italic: 3, # not widely implemented
13
+ underline: 4,
14
+ underscore: 4, # synonym for :underline
15
+ blink: 5,
16
+ rapid_blink: 6, # not widely implemented
17
+ negative: 7, # no reverse because of String#reverse
18
+ concealed: 8,
19
+ strikethrough: 9, # not widely implemented
20
+ black: 30,
21
+ red: 31,
22
+ green: 32,
23
+ yellow: 33,
24
+ blue: 34,
25
+ magenta: 35,
26
+ cyan: 36,
27
+ white: 37,
28
+ on_black: 40,
29
+ on_red: 41,
30
+ on_green: 42,
31
+ on_yellow: 43,
32
+ on_blue: 44,
33
+ on_magenta: 45,
34
+ on_cyan: 46,
35
+ on_white: 47,
36
+ }
37
+
38
+ class << self
39
+ # ColoredString.coloring?
40
+ # Returns true, if the coloring function of this module
41
+ # is switched on, false otherwise.
42
+ #
43
+ # ColoredString.coloring = boolean
44
+ # Turns the coloring on or off globally, so you can easily do
45
+ # this for example:
46
+ # Term::ANSIColor::coloring = STDOUT.isatty
47
+ questionable :coloring, true
48
+
49
+ # <red.bold>Title</red.bold>
50
+ # - u, i/em, b/strong
51
+ def template(string)
52
+ return string # TODO
53
+ end
54
+ end
55
+
56
+ attr_accessor :colors
57
+ def initialize(string = "")
58
+ @string = string
59
+ @colors = Array.new
60
+ end
61
+
62
+ ATTRIBUTES.each do |color, code|
63
+ define_method(color) do
64
+ @colors.push(color)
65
+ self
66
+ end
67
+ end
68
+
69
+ def to_s
70
+ if ! @colors.empty? && self.class.coloring?
71
+ sequences = ""
72
+ @colors.each do |name|
73
+ code = ATTRIBUTES[name]
74
+ sequences << "\e[#{code}m"
75
+ end
76
+ return "#{sequences}#{@string}\e[0m"
77
+ else
78
+ @string
79
+ end
80
+ end
81
+
82
+ def inspect
83
+ "#<ColoredString:#@string>"
84
+ end
85
+
86
+ def raw
87
+ @string
88
+ end
89
+
90
+ def method_missing(method, *args, &block)
91
+ returned = @string.send(method, *args, &block)
92
+ # Bang methods like upcase!
93
+ if returned.is_a?(String) and @string.equal?(returned) # same object
94
+ @string.replace(returned)
95
+ return self
96
+ # upcase
97
+ elsif returned.is_a?(String) and not @string.equal?(returned) # different object
98
+ return self.class.new(returned)
99
+ else # not string, String#split etc
100
+ return returned
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module Enumerable
4
+ # Enumerable#none? is the logical opposite of the builtin method Enumerable#any?. It
5
+ # returns +true+ if and only if _none_ of the elements in the collection satisfy the
6
+ # predicate.
7
+ #
8
+ # If no predicate is provided, Enumerable#none? returns +true+ if and only if _none_ of the
9
+ # elements have a true value (i.e. not +nil+ or +false+).
10
+ #
11
+ # @author Botanicus
12
+ # @from Extensions
13
+ # @since 0.0.3
14
+ # @yield [block] Block which will be evaluated in Project.setttings object.
15
+ # @yieldparam [item] Each item of array-like collection
16
+ # @yieldparam [key, value] Each item of hash-like collection
17
+ # @option params [String, Array<String>] :exclude File or list of files or globs relative to base directory
18
+ # @raise [LoadError] If base directory doesn't exist
19
+ # @raise [ArgumentError] If first argument isn't a glob
20
+ # @return [Array<String>] List of successfully loaded files
21
+ # @example
22
+ # [].none? # => true
23
+ # [nil].none? # => true
24
+ # [5,8,9].none? # => false
25
+ # (1...10).none? { |n| n < 0 } # => true
26
+ # (1...10).none? { |n| n > 0 } # => false
27
+ def none?(&block)
28
+ not self.any?(&block)
29
+ end
30
+ end
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+
3
+ class File
4
+ # Append given chunks to the existing file or create new one.
5
+ # It use <tt>IO#puts</tt> for write to given file.
6
+ #
7
+ # @author Botanicus
8
+ # @since 0.0.3
9
+ # @param [String] file Path to file. You can use <tt>~</tt>, <tt>~user</tt> or similar expressions.
10
+ # @param [String, Object] *chunks Chunks which will be written to the file
11
+ # @raise [Errno::ENOENT] If parent directory of given file doesn't exist
12
+ # @raise [Errno::EACCES] If you don't have permissions to write to given file
13
+ # @return [String] Expanded path to given file
14
+ # @example
15
+ # File.append "~/.bashrc", source # => "/Users/botanicus/.bashrc"
16
+ def self.append(file, *chunks)
17
+ self.write(:puts, "a", file, *chunks)
18
+ end
19
+
20
+ # Append given chunks to the existing file or create new one.
21
+ # It use <tt>IO#print</tt> for write to given file.
22
+ #
23
+ # @author Botanicus
24
+ # @since 0.0.3
25
+ # @param [String] file Path to file. You can use <tt>~</tt>, <tt>~user</tt> or similar expressions.
26
+ # @param [String, Object] *chunks Chunks which will be written to the file
27
+ # @raise [Errno::ENOENT] If parent directory of given file doesn't exist
28
+ # @raise [Errno::EACCES] If you don't have permissions to write to given file
29
+ # @return [String] Expanded path to given file
30
+ # @example
31
+ # File.append "~/.bashrc", source # => "/Users/botanicus/.bashrc"
32
+ def self.add(file, *chunks)
33
+ self.write(:print, "a", file, *chunks)
34
+ end
35
+
36
+ # Create new file and write there given chunks.
37
+ # It use <tt>IO#puts</tt> for write to given file.
38
+ #
39
+ # @author Botanicus
40
+ # @since 0.0.3
41
+ # @param [String] file Path to file. You can use <tt>~</tt>, <tt>~user</tt> or similar expressions.
42
+ # @param [String, Object] *chunks Chunks which will be written to the file
43
+ # @raise [Errno::ENOENT] If parent directory of given file doesn't exist
44
+ # @raise [Errno::EACCES] If you don't have permissions to write to given file
45
+ # @return [String] Expanded path to given file
46
+ # @example
47
+ # File.puts "~/.bashrc", source # => "/Users/botanicus/.bashrc"
48
+ def self.puts(file, *chunks)
49
+ self.write(:puts, "w", file, *chunks)
50
+ end
51
+
52
+ # Create new file and write there given chunks.
53
+ # It use <tt>IO#print</tt> for write to given file.
54
+ #
55
+ # @author Botanicus
56
+ # @since 0.0.3
57
+ # @param [String] file Path to file. You can use <tt>~</tt>, <tt>~user</tt> or similar expressions.
58
+ # @param [String, Object] *chunks Chunks which will be written to the file
59
+ # @raise [Errno::ENOENT] If parent directory of given file doesn't exist
60
+ # @raise [Errno::EACCES] If you don't have permissions to write to given file
61
+ # @return [String] Expanded path to given file
62
+ # @example
63
+ # File.print "~/.bashrc", source # => "/Users/botanicus/.bashrc"
64
+ def self.print(file, *chunks)
65
+ self.write(:print, "w", file, *chunks)
66
+ end
67
+
68
+ # Write data to file with given method.
69
+ #
70
+ # @author Botanicus
71
+ # @since 0.0.3
72
+ # @param [String] file Path to file. You can use <tt>~</tt>, <tt>~user</tt> or similar expressions.
73
+ # @param [String, Object] *chunks Chunks which will be written to the file
74
+ # @raise [Errno::ENOENT] If parent directory of given file doesn't exist
75
+ # @raise [Errno::EACCES] If you don't have permissions to write to given file
76
+ # @return [String] Expanded path to given file
77
+ # @example
78
+ # File.write :printf, "w", "~/.bashrc", "%d %04x", 123, 123 # => "/Users/botanicus/.bashrc"
79
+ def self.write(method, mode, file, *args)
80
+ self.expand_path(file).tap do |path|
81
+ self.open(path, mode) { |file| file.send(method, *args) }
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,180 @@
1
+ # encoding: utf-8
2
+
3
+ class Hash
4
+ # Return duplication of self with all keys non-recursively converted to symbols
5
+ #
6
+ # @author Botanicus
7
+ # @since 0.0.2
8
+ # @return [Hash] A hash with all keys transformed into symbols
9
+ def symbolize_keys
10
+ self.inject(Hash.new) do |result, array|
11
+ result[array.first.to_sym] = array.last
12
+ result
13
+ end
14
+ end
15
+
16
+ # Replace keys in self by coresponding symbols
17
+ #
18
+ # @author Botanicus
19
+ # @since 0.0.2
20
+ # @return [Hash] A hash with all keys transformed into symbols
21
+ def symbolize_keys!
22
+ self.replace(self.symbolize_keys)
23
+ end
24
+
25
+ # Return duplication of self with all keys recursively converted to symbols
26
+ #
27
+ # @author Botanicus
28
+ # @since 0.0.2
29
+ # @return [Hash] A hash with all keys transformed into symbols even in inner hashes
30
+ def deep_symbolize_keys
31
+ self.inject(Hash.new) do |result, array|
32
+ key, value = array.first, array.last
33
+ if value.respond_to?(:symbolize_keys)
34
+ result[key.to_sym] = value.symbolize_keys
35
+ else
36
+ result[key.to_sym] = value
37
+ end
38
+ result
39
+ end
40
+ end
41
+
42
+ # Recursively replace keys in self by coresponding symbols
43
+ #
44
+ # @author Botanicus
45
+ # @since 0.0.2
46
+ # @return [Hash] A hash with all keys transformed into symbols even in inner hashes
47
+ def deep_symbolize_keys!
48
+ self.replace(self.deep_symbolize_keys)
49
+ end
50
+
51
+ # Returns the value of self for each argument and deletes those entries.
52
+ #
53
+ # @author Botanicus
54
+ # @since 0.0.2
55
+ # @param [*args] the keys whose values should be extracted and deleted.
56
+ # @return [Array<Object>] The values of the provided arguments in corresponding order.
57
+ # @api public
58
+ # @example
59
+ # hash = {one: 1, two: 2, three: 3}
60
+ # hash.extract!(:one, :two) # => [1, 2]
61
+ # hash # => {:three => 3}
62
+ def extract!(*args)
63
+ args.map do |arg|
64
+ self.delete(arg)
65
+ end
66
+ end
67
+
68
+ # @author Botanicus
69
+ # @since 0.0.2
70
+ # @return [String] A string formatted for HTML attributes
71
+ # @example
72
+ # {class: "inner", id: "post-#{@post.id}"}.to_html_attrs # => "class='inner' id='post-1'"
73
+ def to_html_attrs
74
+ self.map { |key, value| "#{key}='#{value}'" }.join(" ")
75
+ end
76
+
77
+ # @author Botanicus
78
+ # @since 0.0.2
79
+ # @return [String] A string formatted for URL
80
+ # @example
81
+ # {action: "rate", rating: 2}.to_url_attrs # => "action=rate&rating=2"
82
+ def to_url_attrs
83
+ self.map { |key, value| "#{key}=#{value}" }.join("&")
84
+ end
85
+
86
+ # @author Botanicus
87
+ # @since 0.0.2
88
+ # @return [String] Merge self into hash given as argument
89
+ def reverse_merge(another)
90
+ another.merge(self)
91
+ end
92
+
93
+ # @author Botanicus
94
+ # @since 0.0.2
95
+ # @return [String] Replace self by result of merge self into hash given as argument
96
+ def reverse_merge!(another)
97
+ self.replace(self.reverse_merge(another))
98
+ end
99
+
100
+ # @author Botanicus
101
+ # @since 0.0.2
102
+ # @deprecated
103
+ def to_native
104
+ self.each do |key, value|
105
+ value = case value
106
+ when "true" then true
107
+ when "false" then false
108
+ when "nil" then nil
109
+ when /^\d+$/ then value.to_i
110
+ when /^\d+\.\d+$/ then value.to_f
111
+ else value end
112
+ self[key.to_sym] = value
113
+ end
114
+ return self
115
+ end
116
+
117
+ # Simplier syntax for code such as params[:post] && params[:post][:title]
118
+ #
119
+ # @author Jakub Stastny aka Botanicus
120
+ # @since 0.0.3
121
+ # @param [Object] First argument is the key of the hash, the second one the key of the inner hash selected by the first key etc.
122
+ # @return [Object, nil] The value of the most inner hash if found or nil.
123
+ # @raise [ArgumentError] If you don't specify keys.
124
+ # @raise [IndexError] If you work with final result as with hash, so basically you are trying to call fetch method on string or whatever.
125
+ #
126
+ # @example
127
+ # {a: {b: 1}}.get(:a, :b) # => 1
128
+ # {a: {b: 1}}.get(:a, :b, :c) # => IndexError
129
+ # {a: {b: 1}}.get(:a, :c) # => nil
130
+ def get(*keys)
131
+ raise ArgumentError, "You must specify at least one key" if keys.empty?
132
+ keys.inject(self) do |object, key|
133
+ # Hash#fetch works similar as Hash#[], but [] method is
134
+ # defined for too many objects, also strings and even numbers
135
+ if object.respond_to?(:fetch)
136
+ begin
137
+ object.fetch(key)
138
+ # Hash#fetch raise IndexError if key doesn't exist
139
+ rescue IndexError
140
+ return nil
141
+ end
142
+ else
143
+ raise IndexError, "Object #{object.inspect} isn't hash-like collection"
144
+ end
145
+ end
146
+ end
147
+
148
+ ##
149
+ # Create a hash with *only* key/value pairs in receiver and +allowed+
150
+ #
151
+ # { :one => 1, :two => 2, :three => 3 }.only(:one) #=> { :one => 1 }
152
+ #
153
+ # @param [Array[String, Symbol]] *allowed The hash keys to include.
154
+ #
155
+ # @return [Hash] A new hash with only the selected keys.
156
+ #
157
+ # @api public
158
+ def only(*allowed)
159
+ hash = {}
160
+ allowed.each {|k| hash[k] = self[k] if self.has_key?(k) }
161
+ hash
162
+ end
163
+
164
+ ##
165
+ # Create a hash with all key/value pairs in receiver *except* +rejected+
166
+ #
167
+ # { :one => 1, :two => 2, :three => 3 }.except(:one)
168
+ # #=> { :two => 2, :three => 3 }
169
+ #
170
+ # @param [Array[String, Symbol]] *rejected The hash keys to exclude.
171
+ #
172
+ # @return [Hash] A new hash without the selected keys.
173
+ #
174
+ # @api public
175
+ def except(*rejected)
176
+ hash = self.dup
177
+ rejected.each {|k| hash.delete(k) }
178
+ hash
179
+ end
180
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+
3
+ module Kernel
4
+ # @since 0.0.2
5
+ def metaclass
6
+ class << self
7
+ self
8
+ end
9
+ end
10
+
11
+ # os.home
12
+ def os
13
+ @os ||= OS.parse
14
+ end
15
+
16
+ # @since 0.0.1
17
+ # @example
18
+ # try_require_gem "term/ansicolor", "term-ansicolor"
19
+ # @param [String] library Library to require.
20
+ # @param [String, @optional] gemname Name of gem which contains required library. Will be used for displaying message.
21
+ # @return [Boolean] True if require was successful, false otherwise.
22
+ def try_require_gem(library, gemname = library, options = Hash.new)
23
+ gemname, options = library, gemname if gemname.is_a?(Hash) && options.empty?
24
+ try_require_gem!(library, gemname, options)
25
+ rescue LoadError
26
+ return false
27
+ end
28
+
29
+ # @since 0.0.3
30
+ def try_require_gem!(library, gemname = library, options = Hash.new)
31
+ gemname, options = library, gemname if gemname.is_a?(Hash) && options.empty?
32
+ require library
33
+ rescue LoadError => exception
34
+ message = "Gem #{gemname} isn't installed. Run sudo gem install #{gemname}. (#{exception.inspect})"
35
+ logger = Rango.logger.method(options[:level] || :error)
36
+ callable = defined?(Rango.logger) ? logger : method(:puts)
37
+ callable.call(message)
38
+ raise exception
39
+ end
40
+
41
+ # @since 0.0.3
42
+ def require_gem_or_exit(library, gemname = library, options = Hash.new)
43
+ gemname, options = library, gemname if gemname.is_a?(Hash) && options.empty?
44
+ try_require_gem!(library, gemname, options)
45
+ rescue LoadError
46
+ exit 1
47
+ end
48
+
49
+ # @since 0.0.3
50
+ def try_require(library)
51
+ require library
52
+ rescue LoadError
53
+ return false
54
+ end
55
+
56
+ def command(command)
57
+ puts command
58
+ puts %x[#{command}]
59
+ end
60
+ alias_method :sh, :command
61
+ alias_method :run, :command
62
+
63
+ def quiet(&block)
64
+ old_stdout = STDOUT.dup
65
+ STDOUT.reopen("/dev/null")
66
+ returned = block.call
67
+ STDOUT.reopen(old_stdout)
68
+ return returned
69
+ end
70
+
71
+ def quiet!(&block)
72
+ old_stderr = STDERR.dup
73
+ STDERR.reopen("/dev/null", "a")
74
+ returned = quiet(&block)
75
+ STDERR.reopen(old_stderr)
76
+ return returned
77
+ end
78
+
79
+ # for quick inspection
80
+ # @since 0.0.2
81
+ def puts_and_return(*args)
82
+ puts(*args)
83
+ return *args
84
+ end
85
+
86
+ # @since 0.0.2
87
+ def p_and_return(*args)
88
+ p(*args)
89
+ return *args
90
+ end
91
+ end