rubyexts 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|