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 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, lifted from Rails
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.2
1
+ 1.1.3
@@ -1,24 +1,20 @@
1
-
2
1
  class Array
3
- unless [].respond_to?(:shuffle)
4
- def shuffle
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 receiver in case
112
- # the code wants to disambiguate for some reason
113
- result = instance_exec(@_receivers.last, &block)
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
- # Lifted from Rails' NumberHelper view helper
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)} GB"
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
@@ -1,5 +1,5 @@
1
-
2
1
  module Math
2
+
3
3
  def self.min(a,b)
4
4
  a <= b ? a : b
5
5
  end
@@ -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 dates for two... etc.)
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 rob_s_blog
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
- # def to_phone
89
- # raw, suffix = self.strip.extract(/([0-9\(\)\- \.,]+)(.*)/)
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 <=>) with another string's natural order
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
- it 'should allow creating DSL-style accessors' do
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.2
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: 2012-04-02 00:00:00.000000000Z
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: &2168582060 !ruby/object:Gem::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: *2168582060
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.10
90
+ rubygems_version: 1.8.24
85
91
  signing_key:
86
92
  specification_version: 3
87
93
  summary: Extensions to core classes