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.
- data/CHANGELOG +2 -0
- data/LICENSE +20 -0
- data/README.textile +0 -0
- data/Rakefile +79 -0
- data/TODO.txt +6 -0
- data/lib/rubyexts.rb +102 -0
- data/lib/rubyexts/array.rb +20 -0
- data/lib/rubyexts/attribute.rb +151 -0
- data/lib/rubyexts/capture_io.rb +32 -0
- data/lib/rubyexts/class.rb +177 -0
- data/lib/rubyexts/colored_string.rb +103 -0
- data/lib/rubyexts/enumerable.rb +30 -0
- data/lib/rubyexts/file.rb +84 -0
- data/lib/rubyexts/hash.rb +180 -0
- data/lib/rubyexts/kernel.rb +91 -0
- data/lib/rubyexts/module.rb +53 -0
- data/lib/rubyexts/object.rb +56 -0
- data/lib/rubyexts/object_space.rb +16 -0
- data/lib/rubyexts/os.rb +89 -0
- data/lib/rubyexts/platform.rb +27 -0
- data/lib/rubyexts/random.rb +25 -0
- data/lib/rubyexts/string.rb +92 -0
- data/lib/rubyexts/time.rb +15 -0
- data/lib/rubyexts/time_dsl.rb +62 -0
- data/lib/rubyexts/try_dup.rb +43 -0
- data/lib/rubyexts/unique_array.rb +16 -0
- data/rubyexts.gemspec +36 -0
- data/script/spec +12 -0
- data/spec/rubyexts/array_spec.rb +19 -0
- data/spec/rubyexts/attribute_spec.rb +37 -0
- data/spec/rubyexts/class_spec.rb +1 -0
- data/spec/rubyexts/cli_spec.rb +0 -0
- data/spec/rubyexts/colored_string_spec.rb +9 -0
- data/spec/rubyexts/enumerable_spec.rb +52 -0
- data/spec/rubyexts/file_spec.rb +78 -0
- data/spec/rubyexts/hash_spec.rb +91 -0
- data/spec/rubyexts/kernel_spec.rb +9 -0
- data/spec/rubyexts/module_spec.rb +0 -0
- data/spec/rubyexts/object_space_spec.rb +17 -0
- data/spec/rubyexts/object_spec.rb +57 -0
- data/spec/rubyexts/os_spec.rb +121 -0
- data/spec/rubyexts/platform_spec.rb +0 -0
- data/spec/rubyexts/random_spec.rb +31 -0
- data/spec/rubyexts/string_spec.rb +23 -0
- data/spec/rubyexts/time_dsl_spec.rb +88 -0
- data/spec/rubyexts/time_spec.rb +11 -0
- data/spec/rubyexts/unique_array_spec.rb +0 -0
- data/spec/rubyexts_spec.rb +182 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +16 -0
- metadata +104 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Extends the module object with module and instance accessors for class attributes,
|
4
|
+
# just like the native attr* accessors for instance attributes.
|
5
|
+
#
|
6
|
+
# module AppConfiguration
|
7
|
+
# mattr_accessor :google_api_key
|
8
|
+
# self.google_api_key = "123456789"
|
9
|
+
#
|
10
|
+
# mattr_accessor :paypal_url
|
11
|
+
# self.paypal_url = "www.sandbox.paypal.com"
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# AppConfiguration.google_api_key = "overriding the api key!"
|
15
|
+
class Module
|
16
|
+
def mattr_reader(*syms)
|
17
|
+
syms.each do |sym|
|
18
|
+
next if sym.is_a?(Hash)
|
19
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
20
|
+
unless defined? @@#{sym}
|
21
|
+
@@#{sym} = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.#{sym}
|
25
|
+
@@#{sym}
|
26
|
+
end
|
27
|
+
|
28
|
+
def #{sym}
|
29
|
+
@@#{sym}
|
30
|
+
end
|
31
|
+
EOS
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def mattr_writer(*syms)
|
36
|
+
syms.each do |sym|
|
37
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
38
|
+
unless defined? @@#{sym}
|
39
|
+
@@#{sym} = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.#{sym}=(obj)
|
43
|
+
@@#{sym} = obj
|
44
|
+
end
|
45
|
+
EOS
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def mattr_accessor(*syms)
|
50
|
+
mattr_reader(*syms)
|
51
|
+
mattr_writer(*syms)
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
|
5
|
+
# and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
|
6
|
+
#
|
7
|
+
# Invokes the method identified by the symbol +method+, passing it any arguments
|
8
|
+
# and/or the block specified, just like the regular Ruby <tt>Object#send</tt> does.
|
9
|
+
#
|
10
|
+
# @author Botanicus
|
11
|
+
# @since 0.0.3
|
12
|
+
# @return [Object, nil] Return value of object.send(method) if object respond to method or nil
|
13
|
+
# @param [Symbol] Method which will be called on object if object respond to this method
|
14
|
+
# @param [Object, optional] Arguments for +method+ argument
|
15
|
+
# @yield [block, optional] Block for +method+ argument
|
16
|
+
# @example
|
17
|
+
# @post.try(:name) # instead @post && @post.name
|
18
|
+
# eBook.try(:find, 1)
|
19
|
+
# @post.try(:collect) { |p| p.name }
|
20
|
+
def try(method, *args, &block)
|
21
|
+
self.send(method, *args, &block) if self.respond_to?(method)
|
22
|
+
end
|
23
|
+
|
24
|
+
# The opposite of <tt>#nil?</tt>.
|
25
|
+
#
|
26
|
+
# @author Botanicus
|
27
|
+
# @since 0.0.3
|
28
|
+
# @return [true, false] True if self is nil, false otherwise
|
29
|
+
def not_nil?
|
30
|
+
not self.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Defines a instance method on class of the object.
|
34
|
+
#
|
35
|
+
# @author Botanicus
|
36
|
+
# @since 0.0.3
|
37
|
+
# @param [Symbol] Method name
|
38
|
+
# @param [Method, Proc, optional] +Method+ or +Proc+ which will be used as body of the method
|
39
|
+
# @yield [block] Block which will be used as body of the method
|
40
|
+
# @return [Object] First (and only) item of the array
|
41
|
+
# @see <tt>Module#define_singleton_method</tt> for define method on singleton class
|
42
|
+
# @example
|
43
|
+
# class Experiment
|
44
|
+
# def method_generator
|
45
|
+
# define_instance_method(:new_method) do |arg|
|
46
|
+
# puts "Method :new_method called with #{arg}"
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
# Experiment.new.methods.include?(:new_method) # => false
|
51
|
+
# Experiment.new.method_generator
|
52
|
+
# Experiment.new.methods.include?(:new_method) # => true
|
53
|
+
def define_instance_method(*args, &block)
|
54
|
+
self.class.send(:define_method, *args, &block)
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ObjectSpace
|
4
|
+
# Returns all classes existing in runtime
|
5
|
+
#
|
6
|
+
# @author Botanicus
|
7
|
+
# @since 0.0.3
|
8
|
+
# @return [Array<Class>] List of all classes loaded into runtime
|
9
|
+
def self.classes
|
10
|
+
Array.new.tap do |objects|
|
11
|
+
self.each_object(Class) do |object|
|
12
|
+
objects << object
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/rubyexts/os.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class OS
|
4
|
+
# Takes ENV or another hash-like object and convert it into OS instance
|
5
|
+
#
|
6
|
+
# @author Botanicus
|
7
|
+
# @since 0.0.3
|
8
|
+
# @param [ENV, Hash] ENV or another hash-like object
|
9
|
+
# @return [OS] Instance of OS
|
10
|
+
# @example
|
11
|
+
# OS.parse
|
12
|
+
# OS.parse("HOME" => "/Users/botanicus")
|
13
|
+
def self.parse(original_env = ENV)
|
14
|
+
input = original_env.select { |key, value| key.match(/^[a-zA-Z][a-zA-Z_]*$/) }
|
15
|
+
result = Hash.new
|
16
|
+
input.each { |key, value| result[key.downcase.to_sym] = value }
|
17
|
+
self.new(result, original_env)
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :env, :original_env
|
21
|
+
def initialize(env, original_env = env)
|
22
|
+
@env, @original_env = env, original_env
|
23
|
+
self.keys.each do |key|
|
24
|
+
if key.match(/(path|lib)$/)
|
25
|
+
# OS.path
|
26
|
+
# => ["/bin", "/usr/bin", "/sbin", "/usr/sbin"]
|
27
|
+
define_singleton_method(key) do
|
28
|
+
@env[key].split(":").uniq.sort
|
29
|
+
end
|
30
|
+
elsif @env[key].match(/^\d+$/)
|
31
|
+
define_singleton_method(key) { @env[key].to_i }
|
32
|
+
elsif @env[key].empty?
|
33
|
+
define_singleton_method(key) { nil }
|
34
|
+
else
|
35
|
+
# OS.home
|
36
|
+
# => "/Users/botanicus"
|
37
|
+
define_singleton_method(key) do
|
38
|
+
case value = @env[key]
|
39
|
+
when /^\d+$/ then value.to_i
|
40
|
+
when /^\d+\.\d+$/ then value.to_f
|
41
|
+
when /^true$/i then true
|
42
|
+
when /^false$/i then false
|
43
|
+
when /^$/ then nil
|
44
|
+
else value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get value for given key or nil
|
52
|
+
#
|
53
|
+
# @author Botanicus
|
54
|
+
# @since 0.0.3
|
55
|
+
# @param [Symbol] Key
|
56
|
+
# @return [OS] Instance of OS
|
57
|
+
# @example
|
58
|
+
# os[:home]
|
59
|
+
def [](key)
|
60
|
+
self.send(key) if self.keys.include?(key.to_sym)
|
61
|
+
end
|
62
|
+
|
63
|
+
def ==(other)
|
64
|
+
same_keys = self.keys == other.keys
|
65
|
+
same_values = self.keys.all? { |key| self[key] == other[key] }
|
66
|
+
same_keys && same_values
|
67
|
+
end
|
68
|
+
|
69
|
+
def keys
|
70
|
+
@env.keys.sort
|
71
|
+
end
|
72
|
+
|
73
|
+
def inspect
|
74
|
+
string = "#<OS keys=[%s]>"
|
75
|
+
format = lambda { |key| "#{key}=#{self.send(key).inspect}" }
|
76
|
+
inner = self.keys.sort.map(&format).join(", ")
|
77
|
+
string % inner
|
78
|
+
end
|
79
|
+
|
80
|
+
# TODO
|
81
|
+
def root?
|
82
|
+
self.uid.eql?(0)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def method_missing(name, *args, &block)
|
87
|
+
super(name, *args, &block) unless args.empty? && block.nil?
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RubyExts
|
4
|
+
class Platform
|
5
|
+
class << self
|
6
|
+
def match?(platform)
|
7
|
+
!! RUBY_PLATFORM.match(/#{platform}/i)
|
8
|
+
end
|
9
|
+
|
10
|
+
def windows?
|
11
|
+
self.match?("mswin|mingw")
|
12
|
+
end
|
13
|
+
|
14
|
+
def linux?
|
15
|
+
self.match?("linux")
|
16
|
+
end
|
17
|
+
|
18
|
+
def osx?
|
19
|
+
self.match?("-darwin")
|
20
|
+
end
|
21
|
+
|
22
|
+
def unix?
|
23
|
+
self.linux? or self.osx?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Array
|
4
|
+
# Returns random item from the array
|
5
|
+
#
|
6
|
+
# @author Botanicus
|
7
|
+
# @since 0.0.2
|
8
|
+
# @return [Object] Random item from array
|
9
|
+
def rand
|
10
|
+
self[Kernel.rand(length)]
|
11
|
+
end
|
12
|
+
alias_method :random, :rand
|
13
|
+
end
|
14
|
+
|
15
|
+
class Range
|
16
|
+
# Returns random item from the array
|
17
|
+
#
|
18
|
+
# @author Botanicus
|
19
|
+
# @since 0.0.2
|
20
|
+
# @return [Object] Random item from range
|
21
|
+
def rand
|
22
|
+
self.min + Kernel.rand(self.max)
|
23
|
+
end
|
24
|
+
alias_method :random, :rand
|
25
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class String
|
4
|
+
# Transform self into titlecased string.
|
5
|
+
#
|
6
|
+
# @author Botanicus
|
7
|
+
# @since 0.0.3
|
8
|
+
# @return [String] Titlecased string
|
9
|
+
# @example
|
10
|
+
# "hello world!".titlecase # => "Hello World!"
|
11
|
+
def titlecase
|
12
|
+
self.gsub(/\b./) { $&.upcase }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Transform self to +ColoredString+
|
16
|
+
# @since 0.0.1
|
17
|
+
# @example
|
18
|
+
# "message".colorize.red.bold
|
19
|
+
# @param [type] name explanation
|
20
|
+
# @return [String] Transfrom self to +ColoredString+
|
21
|
+
def colorize
|
22
|
+
require_relative "colored_string"
|
23
|
+
ColoredString.new(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove(pattern)
|
27
|
+
self.gsub(pattern, "")
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove!(pattern)
|
31
|
+
self.gsub!(pattern, "")
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Convert to snake case.
|
36
|
+
#
|
37
|
+
# "FooBar".snake_case #=> "foo_bar"
|
38
|
+
# "HeadlineCNNNews".snake_case #=> "headline_cnn_news"
|
39
|
+
# "CNN".snake_case #=> "cnn"
|
40
|
+
#
|
41
|
+
# @return [String] Receiver converted to snake case.
|
42
|
+
#
|
43
|
+
# @api public
|
44
|
+
def snake_case
|
45
|
+
return self.downcase if self =~ /^[A-Z]+$/
|
46
|
+
self.gsub(/([A-Z]+)(?=[A-Z][a-z]?)|\B[A-Z]/, '_\&') =~ /_*(.*)/
|
47
|
+
return $+.downcase
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Convert to camel case.
|
52
|
+
#
|
53
|
+
# "foo_bar".camel_case #=> "FooBar"
|
54
|
+
#
|
55
|
+
# @return [String] Receiver converted to camel case.
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
def camel_case
|
59
|
+
return self if self !~ /_/ && self =~ /[A-Z]+.*/
|
60
|
+
split('_').map{|e| e.capitalize}.join
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Convert a path string to a constant name.
|
65
|
+
#
|
66
|
+
# "merb/core_ext/string".to_const_string #=> "Merb::CoreExt::String"
|
67
|
+
#
|
68
|
+
# @return [String] Receiver converted to a constant name.
|
69
|
+
#
|
70
|
+
# @api public
|
71
|
+
def to_const_string
|
72
|
+
gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Convert a constant name to a path, assuming a conventional structure.
|
77
|
+
#
|
78
|
+
# "FooBar::Baz".to_const_path # => "foo_bar/baz"
|
79
|
+
#
|
80
|
+
# @return [String] Path to the file containing the constant named by receiver
|
81
|
+
# (constantized string), assuming a conventional structure.
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
def to_const_path
|
85
|
+
snake_case.gsub(/::/, "/")
|
86
|
+
end
|
87
|
+
|
88
|
+
# For Rack
|
89
|
+
# @since 0.0.2
|
90
|
+
# @todo Is it still required?
|
91
|
+
alias_method :each, :each_line
|
92
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Time
|
4
|
+
# How long it takes to run the block in seconds
|
5
|
+
#
|
6
|
+
# @author Botanicus
|
7
|
+
# @since 0.0.3
|
8
|
+
# @return [Float] How long it takes to run the block in seconds
|
9
|
+
# @example
|
10
|
+
# Time.timer { sleep 2 } # => 2.030802
|
11
|
+
def self.timer(&block)
|
12
|
+
start = Time.now.tap { block.call }
|
13
|
+
return Time.now - start
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# stolen from merb-helpers
|
4
|
+
|
5
|
+
# Provides a a simple way of calling time units and to see the elapsed time between 2 moments
|
6
|
+
# @example
|
7
|
+
# 142.minutes => returns a value in seconds
|
8
|
+
# 7.days => returns a value in seconds
|
9
|
+
# 1.week => returns a value in seconds
|
10
|
+
# 2.weeks.ago => returns a date
|
11
|
+
# 1.year.since(time) => returns a date
|
12
|
+
# 5.months.since(2.weeks.from_now) => returns a date
|
13
|
+
module TimeDSL
|
14
|
+
def second
|
15
|
+
self * 1
|
16
|
+
end
|
17
|
+
alias_method :seconds, :second
|
18
|
+
|
19
|
+
def minute
|
20
|
+
self * 60
|
21
|
+
end
|
22
|
+
alias_method :minutes, :minute
|
23
|
+
|
24
|
+
def hour
|
25
|
+
self * 3600
|
26
|
+
end
|
27
|
+
alias_method :hours, :hour
|
28
|
+
|
29
|
+
def day
|
30
|
+
self * 86400
|
31
|
+
end
|
32
|
+
alias_method :days, :day
|
33
|
+
|
34
|
+
def week
|
35
|
+
self * 604800
|
36
|
+
end
|
37
|
+
alias_method :weeks, :week
|
38
|
+
|
39
|
+
def month
|
40
|
+
self * 2592000
|
41
|
+
end
|
42
|
+
alias_method :months, :month
|
43
|
+
|
44
|
+
def year
|
45
|
+
self * 31471200
|
46
|
+
end
|
47
|
+
alias_method :years, :year
|
48
|
+
|
49
|
+
# Reads best without arguments: 10.minutes.ago
|
50
|
+
def ago(time = ::Time.now)
|
51
|
+
time - self
|
52
|
+
end
|
53
|
+
alias :until :ago
|
54
|
+
|
55
|
+
# Reads best with argument: 10.minutes.since(time)
|
56
|
+
def since(time = ::Time.now)
|
57
|
+
time + self
|
58
|
+
end
|
59
|
+
alias :from_now :since
|
60
|
+
end
|
61
|
+
|
62
|
+
Numeric.send :include, TimeDSL
|