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 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