iron-extensions 1.1.2 → 1.1.3
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/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
|