iron-extensions 1.1.2 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -0
- data/README.rdoc +22 -9
- data/Version.txt +1 -1
- data/lib/iron/extensions/array.rb +7 -11
- data/lib/iron/extensions/class.rb +36 -0
- data/lib/iron/extensions/dsl_proxy.rb +8 -8
- data/lib/iron/extensions/fixnum.rb +5 -4
- data/lib/iron/extensions/math.rb +1 -1
- data/lib/iron/extensions/string.rb +5 -21
- data/spec/extensions/array_spec.rb +15 -0
- data/spec/extensions/dsl_builder_spec.rb +10 -1
- data/spec/extensions/dsl_proxy_spec.rb +6 -1
- data/spec/extensions/enumerable_spec.rb +4 -0
- data/spec/extensions/numeric_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -1
- metadata +11 -5
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 1.1.3 / 2013-09-04
|
2
|
+
|
3
|
+
* Flesh out DslProxy#exec to allow specifying one or more yielded values
|
4
|
+
* Add #dsl_flag as class method to better support boolean attributes in DSLs
|
5
|
+
* Tweak Fixnum#to_human_size to correct some minor issues with output formatting
|
6
|
+
* Remove Array#shuffle and Array#shuffle! as they are core methods as of Ruby 1.8.7
|
7
|
+
* Deprecate Array#rand and Array#rand! in favor of the core Array#sample method
|
8
|
+
* Improve spec coverage and commenting
|
9
|
+
|
1
10
|
== 1.1.2 / 2012-03-30
|
2
11
|
|
3
12
|
* Rename Enumerable#to_hash to #convert_to_hash to resolve ActiveRecord conflict
|
data/README.rdoc
CHANGED
@@ -8,14 +8,6 @@ Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
|
8
8
|
|
9
9
|
== ADDED EXTENSIONS
|
10
10
|
|
11
|
-
* Array#rand / Array#rand! - pull n random items from the array
|
12
|
-
|
13
|
-
[1,2,3,4,5].rand(2) # => [2, 5]
|
14
|
-
|
15
|
-
* Array#shuffle / Array#shuffle! - randomly reorder the array
|
16
|
-
|
17
|
-
[1,2,3,4,5].shuffle # => [2,4,1,5,3]
|
18
|
-
|
19
11
|
* Array#list_join - join as a list, ignoring blank/nil entries
|
20
12
|
|
21
13
|
[1, 2, nil, '', 'count'].list_join # => '1, 2, count'
|
@@ -32,6 +24,17 @@ Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
|
32
24
|
name 'Project Omega'
|
33
25
|
end
|
34
26
|
builder.name # => 'Project Omega'
|
27
|
+
|
28
|
+
* Class#dsl_flag - same as above, but designed for boolean values
|
29
|
+
|
30
|
+
class AnotherBuilder
|
31
|
+
dsl_flag :awesome
|
32
|
+
end
|
33
|
+
|
34
|
+
builder = AnotherBuilder
|
35
|
+
builder.awesome? # => false on uninitialized value
|
36
|
+
builder.awesome! # => sets @awesome to true
|
37
|
+
builder.awesome true # ditto, same style as dsl_accessor above
|
35
38
|
|
36
39
|
* Enumerable#to_hash - convert an array or other enumerable to a hash using a block or constant
|
37
40
|
|
@@ -47,7 +50,7 @@ Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
|
47
50
|
end
|
48
51
|
|
49
52
|
* Fixnum#blank? - always false
|
50
|
-
* Fixnum#to_human_size - size to MB/GB/whatever,
|
53
|
+
* Fixnum#to_human_size - size to MB/GB/whatever, adapted from Rails
|
51
54
|
|
52
55
|
123456.to_human_size # => "120.5 KB"
|
53
56
|
|
@@ -68,6 +71,12 @@ Helpful extensions to core Ruby classes, plus a little sugar for common patterns
|
|
68
71
|
|
69
72
|
* Nil#blank? - always true
|
70
73
|
|
74
|
+
* Numeric#to_display - pretty display of numbers with options for number of decimal places and inclusion of thousands separator
|
75
|
+
|
76
|
+
5000.to_display # => 5,000
|
77
|
+
100.to_display(2) # => 100.00
|
78
|
+
2105.2348.to_display(2) # => 2,105.23
|
79
|
+
|
71
80
|
* Numeric#bound - bound a given number to a range
|
72
81
|
|
73
82
|
4.bound(5,10) # => 5
|
@@ -134,3 +143,7 @@ To install, simply run:
|
|
134
143
|
RVM users should drop the 'sudo':
|
135
144
|
|
136
145
|
gem install iron-extensions
|
146
|
+
|
147
|
+
Then simply require the library:
|
148
|
+
|
149
|
+
require 'iron/extensions'
|
data/Version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.3
|
@@ -1,24 +1,20 @@
|
|
1
|
-
|
2
1
|
class Array
|
3
|
-
|
4
|
-
|
5
|
-
sort_by { Kernel.rand }
|
6
|
-
end
|
7
|
-
|
8
|
-
def shuffle!
|
9
|
-
self.replace shuffle
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
2
|
+
|
3
|
+
# DEPRECATED: as of Ruby 1.9, you should use Array#sample instead
|
13
4
|
def rand(count = 1)
|
5
|
+
warn("[DEPRECATION] Array#rand is deprecated - use Array#sample instead")
|
14
6
|
shuffle[0...count]
|
15
7
|
end
|
16
8
|
|
9
|
+
# DEPRECATED: as of Ruby 1.9, you should use Array#sample instead
|
17
10
|
def rand!(count = 1)
|
11
|
+
warn("[DEPRECATION] Array#rand is deprecated - use Array#sample instead")
|
18
12
|
self.replace rand(count)
|
19
13
|
end
|
20
14
|
|
15
|
+
# Join an array's values ignoring blank entries
|
21
16
|
def list_join(sep = ', ')
|
22
17
|
self.select{|e| !e.blank?}.join(sep)
|
23
18
|
end
|
19
|
+
|
24
20
|
end
|
@@ -1,5 +1,23 @@
|
|
1
1
|
class Class
|
2
2
|
|
3
|
+
# Provides a DSL-friendly way to set values. Similar to attr_accessor, but
|
4
|
+
# supports setting values like so:
|
5
|
+
#
|
6
|
+
# class Widget
|
7
|
+
# dsl_accessor :size
|
8
|
+
# end
|
9
|
+
# @w = Widget.new
|
10
|
+
# @w.size = 5 # normal setter, same as...
|
11
|
+
# @w.size 5 # note the lack of explicit = sign
|
12
|
+
# puts @w.size # still get reader access
|
13
|
+
#
|
14
|
+
# Useful in DslProxy blocks:
|
15
|
+
#
|
16
|
+
# DslProxy.exec(Widget.new) do
|
17
|
+
# size 10 # sets size to 10, as expected
|
18
|
+
# size = 10 # fails, creates local variable 'size' instead of invoking Widget#size
|
19
|
+
# end
|
20
|
+
#
|
3
21
|
def dsl_accessor(*keys)
|
4
22
|
keys.each do |key|
|
5
23
|
class_eval "def #{key}(val = :__UNDEFINED); @#{key} = val unless val == :__UNDEFINED; @#{key}; end"
|
@@ -7,4 +25,22 @@ class Class
|
|
7
25
|
end
|
8
26
|
end
|
9
27
|
|
28
|
+
# Like #dsl_accessor, but adds imperative and query versions of the keys as well to set the
|
29
|
+
# flag to true and to query the true-ness of the flag.
|
30
|
+
#
|
31
|
+
# class Widget
|
32
|
+
# dsl_flag :heavy
|
33
|
+
# end
|
34
|
+
# @w = Widget.new
|
35
|
+
# @w.heavy? # => false
|
36
|
+
# @w.heavy! # now is true
|
37
|
+
#
|
38
|
+
def dsl_flag(*keys)
|
39
|
+
dsl_accessor(*keys)
|
40
|
+
keys.each do |key|
|
41
|
+
class_eval "def #{key}!; @#{key} = true; end"
|
42
|
+
class_eval "def #{key}?; @#{key} === true; end"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
10
46
|
end
|
@@ -64,7 +64,7 @@ class DslProxy < BasicObject
|
|
64
64
|
#
|
65
65
|
# If the receiver doesn't respond_to? a method, any missing methods
|
66
66
|
# will be proxied to the enclosing context.
|
67
|
-
def self.exec(receiver, &block) # :yields: receiver
|
67
|
+
def self.exec(receiver, *to_yield, &block) # :yields: receiver
|
68
68
|
# Find the context within which the block was defined
|
69
69
|
context = ::Kernel.eval('self', block.binding)
|
70
70
|
|
@@ -78,7 +78,7 @@ class DslProxy < BasicObject
|
|
78
78
|
end
|
79
79
|
|
80
80
|
# Exec the block and return the result
|
81
|
-
proxy._proxy(receiver, &block)
|
81
|
+
proxy._proxy(receiver, *to_yield, &block)
|
82
82
|
end
|
83
83
|
|
84
84
|
# Simple state setup
|
@@ -88,7 +88,7 @@ class DslProxy < BasicObject
|
|
88
88
|
@_context = context
|
89
89
|
end
|
90
90
|
|
91
|
-
def _proxy(receiver, &block) # :yields: receiver
|
91
|
+
def _proxy(receiver, *to_yield, &block) # :yields: receiver
|
92
92
|
# Sanity!
|
93
93
|
raise 'Cannot proxy with a DslProxy as receiver!' if receiver.respond_to?(:_to_dsl_proxy)
|
94
94
|
|
@@ -99,7 +99,6 @@ class DslProxy < BasicObject
|
|
99
99
|
unless var.starts_with?('@_')
|
100
100
|
value = @_context.instance_variable_get(var.to_s)
|
101
101
|
@_instance_original_values[var] = value
|
102
|
-
#instance_variable_set(var, value)
|
103
102
|
instance_eval "#{var} = value"
|
104
103
|
end
|
105
104
|
end
|
@@ -108,9 +107,11 @@ class DslProxy < BasicObject
|
|
108
107
|
# Save the dsl target as our receiver for proxying
|
109
108
|
_push_receiver(receiver)
|
110
109
|
|
111
|
-
# Run the block with ourselves as the new "self", passing the
|
112
|
-
# the code wants to disambiguate for some reason
|
113
|
-
|
110
|
+
# Run the block with ourselves as the new "self", passing the given yieldable(s) or
|
111
|
+
# the receiver in case the code wants to disambiguate for some reason
|
112
|
+
to_yield = [receiver] if to_yield.empty?
|
113
|
+
to_yield = to_yield.first(block.arity)
|
114
|
+
result = instance_exec(*to_yield, &block)
|
114
115
|
|
115
116
|
# Pop the last receiver off the stack
|
116
117
|
_pop_receiver
|
@@ -121,7 +122,6 @@ class DslProxy < BasicObject
|
|
121
122
|
@_context.instance_variables.each do |var|
|
122
123
|
unless var.starts_with?('@_')
|
123
124
|
value = instance_eval("#{var}")
|
124
|
-
#value = instance_variable_get("#{var}")
|
125
125
|
if @_instance_original_values[var] != value
|
126
126
|
@_context.instance_variable_set(var.to_s, value)
|
127
127
|
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
|
2
1
|
class Fixnum
|
3
|
-
|
2
|
+
|
3
|
+
# Adapted from Rails' NumberHelper view helper
|
4
4
|
def to_human_size(precision=1)
|
5
5
|
size = Kernel.Float(self)
|
6
6
|
case
|
7
7
|
when size.to_i == 1 then
|
8
8
|
"1 Byte"
|
9
9
|
when size < 1024 then
|
10
|
-
"#{size} Bytes"
|
10
|
+
"#{size.to_i} Bytes"
|
11
11
|
when size < 1024*1024 then
|
12
12
|
"#{(size / 1024).to_display(precision)} KB"
|
13
13
|
when size < 1024*1024*1024 then
|
@@ -15,7 +15,7 @@ class Fixnum
|
|
15
15
|
when size < 1024*1024*1024*1024 then
|
16
16
|
"#{(size / (1024*1024*1024)).to_display(precision)} GB"
|
17
17
|
else
|
18
|
-
"#{(size / (1024*1024*1024*1024)).to_display(precision)}
|
18
|
+
"#{(size / (1024*1024*1024*1024)).to_display(precision)} TB"
|
19
19
|
end
|
20
20
|
rescue
|
21
21
|
nil
|
@@ -24,4 +24,5 @@ class Fixnum
|
|
24
24
|
def blank?
|
25
25
|
false
|
26
26
|
end
|
27
|
+
|
27
28
|
end
|
data/lib/iron/extensions/math.rb
CHANGED
@@ -15,7 +15,7 @@ class String
|
|
15
15
|
self.insert(-1, str.to_s)
|
16
16
|
end
|
17
17
|
|
18
|
-
# Date.parse sucks hard (assumes EU formatting, for one, does the wrong thing with 2 digit
|
18
|
+
# Date.parse sucks hard (assumes EU formatting, for one, does the wrong thing with 2 digit years for two... etc.)
|
19
19
|
# so we have this here as our personal, bona-fide date parsing helper.
|
20
20
|
def to_date
|
21
21
|
us_format = /^([0-9]{1,2})[-\/\.]([0-9]{1,2})[-\/\.]([0-9]+)$/ # US standard MM/DD/YYYY, allowing for 2 digit year
|
@@ -75,7 +75,7 @@ class String
|
|
75
75
|
# To a permalink-style string rep, removing all non-word characters and dasherizing all spaces
|
76
76
|
def to_dashcase
|
77
77
|
s = self.dup
|
78
|
-
s.gsub!(/\'/,'') # remove ' from rob's, so we don't get
|
78
|
+
s.gsub!(/\'/,'') # remove ' from rob's, so we don't get rob-s-blog
|
79
79
|
s.gsub!(/\W+/, ' ') # all non-word chars to spaces
|
80
80
|
s.gsub!('_',' ') # we don't like underscores
|
81
81
|
s.strip! # ooh la la
|
@@ -85,24 +85,8 @@ class String
|
|
85
85
|
end
|
86
86
|
alias_method :to_permalink, :to_dashcase
|
87
87
|
|
88
|
-
#
|
89
|
-
#
|
90
|
-
# raw.gsub!(/[^0-9\+\,]+/,'')
|
91
|
-
# raw.gsub!(/^\+?1/, '')
|
92
|
-
# raw, pause = raw.extract(/([0-9]+)(.*)/)
|
93
|
-
# count = raw.length
|
94
|
-
# if count == 7 || count == 10
|
95
|
-
# area, first, last = raw.extract(/([0-9]{3})?([0-9]{3})([0-9]{4})/)
|
96
|
-
# area ||= Settings[:site][:phone].default_area_code || '919'
|
97
|
-
# suffix = ' ' + suffix unless suffix.blank?
|
98
|
-
# pattern = Settings[:site][:phone].format || '(area) first-last'
|
99
|
-
# res = pattern.sub('area', area).sub('first', first).sub('last', last) + pause + suffix
|
100
|
-
# return res
|
101
|
-
# else
|
102
|
-
# return self
|
103
|
-
# end
|
104
|
-
# end
|
105
|
-
|
88
|
+
# Truncate a string to no more than len characters, honoring
|
89
|
+
# word boundaries (whitespace and - character)
|
106
90
|
def smart_truncate(len = 30, ending = '...')
|
107
91
|
len = Math.max(len, 5)
|
108
92
|
return self if self.length <= len
|
@@ -112,7 +96,7 @@ class String
|
|
112
96
|
s.reverse + ending
|
113
97
|
end
|
114
98
|
|
115
|
-
# Returns an array that can be compared (eg via
|
99
|
+
# Returns an array that can be compared (eg via Array#sort) with another string's natural order
|
116
100
|
# to implement natural order sorting ("Bob123" => ['BOB', 123])
|
117
101
|
def natural_order(nocase=true)
|
118
102
|
i = true
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe Array do
|
2
|
+
|
3
|
+
it 'should join lists ignoring blank entries' do
|
4
|
+
['word', nil, '', 'end'].list_join('-').should == 'word-end'
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'should handle empty arrays while joining lists' do
|
8
|
+
[].list_join.should == ''
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should handle list joins with only blank entries' do
|
12
|
+
[nil, '', nil].list_join.should == ''
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
describe DslBuilder do
|
2
2
|
|
3
|
-
|
3
|
+
# TODO: break this out a bit...
|
4
|
+
it 'should allow using DSL-style accessors' do
|
4
5
|
class MyBuilder < DslBuilder
|
5
6
|
dsl_accessor :name
|
7
|
+
dsl_flag :flagged
|
6
8
|
end
|
7
9
|
builder = MyBuilder.new
|
8
10
|
|
@@ -10,11 +12,18 @@ describe DslBuilder do
|
|
10
12
|
builder.name 'ProjectX'
|
11
13
|
builder.name.should == 'ProjectX'
|
12
14
|
|
15
|
+
builder.flagged?.should be_false
|
16
|
+
builder.flagged = true
|
17
|
+
builder.flagged?.should be_true
|
18
|
+
builder.flagged = false
|
19
|
+
|
13
20
|
# Test as part of DslProxy usage (common case)
|
14
21
|
DslProxy.exec(builder) do
|
15
22
|
name 'Project Omega'
|
23
|
+
flagged!
|
16
24
|
end
|
17
25
|
builder.name.should == 'Project Omega'
|
26
|
+
builder.flagged?.should be_true
|
18
27
|
end
|
19
28
|
|
20
29
|
end
|
@@ -45,7 +45,7 @@ describe DslProxy do
|
|
45
45
|
@foo.should == 'no bar!'
|
46
46
|
end
|
47
47
|
|
48
|
-
it 'should proxy missing methods on the receiver to the context' do
|
48
|
+
it 'should proxy missing methods on the receiver to the calling context' do
|
49
49
|
class TestContext
|
50
50
|
def bar
|
51
51
|
'something'
|
@@ -93,6 +93,11 @@ describe DslProxy do
|
|
93
93
|
local_var.should == 11
|
94
94
|
end
|
95
95
|
|
96
|
+
it 'should pass additional args to block as argument' do
|
97
|
+
l = lambda {|arg1, arg2| arg1 + arg2}
|
98
|
+
DslProxy.exec(Object.new, 5, 1, &l).should == 6
|
99
|
+
end
|
100
|
+
|
96
101
|
it 'should put it all together' do
|
97
102
|
@knob_count = 5
|
98
103
|
controls = ControlBuilder.define do
|
@@ -5,6 +5,10 @@ describe Enumerable do
|
|
5
5
|
[1,2,3].convert_to_hash.should == {1 => nil, 2 => nil, 3 => nil}
|
6
6
|
end
|
7
7
|
|
8
|
+
it 'should accept a default value' do
|
9
|
+
[:a, :b].convert_to_hash(false).should == {:a => false, :b => false}
|
10
|
+
end
|
11
|
+
|
8
12
|
it 'should accept a block to set hash values' do
|
9
13
|
[:a, :b, :c].convert_to_hash {|k| k.to_s.upcase}.should == {:a => 'A', :b => 'B', :c => 'C'}
|
10
14
|
end
|
@@ -6,7 +6,7 @@ describe Numeric do
|
|
6
6
|
12345.to_display.should == '12,345'
|
7
7
|
123450000066666234234.should be_an_instance_of(Bignum)
|
8
8
|
123450000066666234234.to_display.should == '123,450,000,066,666,234,234'
|
9
|
-
0.0004.to_display
|
9
|
+
0.0004.to_display.should == '0.0004'
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'should display correctly when negative' do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# Require our library
|
2
2
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'iron', 'extensions'))
|
3
3
|
|
4
|
+
# Config RSpec options
|
4
5
|
RSpec.configure do |config|
|
5
|
-
#config.add_formatter 'documentation'
|
6
6
|
config.color = true
|
7
|
+
config.add_formatter 'documentation'
|
7
8
|
config.backtrace_clean_patterns = [/rspec/]
|
8
9
|
end
|
9
10
|
|
11
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iron-extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-09-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,7 +21,12 @@ dependencies:
|
|
21
21
|
version: '2.6'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.6'
|
25
30
|
description: Adds common extensions to core Ruby classes
|
26
31
|
email:
|
27
32
|
- rob@irongaze.com
|
@@ -46,6 +51,7 @@ files:
|
|
46
51
|
- lib/iron/extensions/string.rb
|
47
52
|
- lib/iron/extensions/symbol.rb
|
48
53
|
- lib/iron/extensions.rb
|
54
|
+
- spec/extensions/array_spec.rb
|
49
55
|
- spec/extensions/dsl_builder_spec.rb
|
50
56
|
- spec/extensions/dsl_proxy_spec.rb
|
51
57
|
- spec/extensions/enumerable_spec.rb
|
@@ -81,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
87
|
version: '0'
|
82
88
|
requirements: []
|
83
89
|
rubyforge_project:
|
84
|
-
rubygems_version: 1.8.
|
90
|
+
rubygems_version: 1.8.24
|
85
91
|
signing_key:
|
86
92
|
specification_version: 3
|
87
93
|
summary: Extensions to core classes
|