activesupport-refinements 0.0.1

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.
Files changed (120) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +32 -0
  5. data/Rakefile +1 -0
  6. data/activesupport-refinements.gemspec +21 -0
  7. data/lib/active_support/refinements/core_ext/array.rb +7 -0
  8. data/lib/active_support/refinements/core_ext/array/access.rb +56 -0
  9. data/lib/active_support/refinements/core_ext/array/conversions.rb +224 -0
  10. data/lib/active_support/refinements/core_ext/array/extract_options.rb +31 -0
  11. data/lib/active_support/refinements/core_ext/array/grouping.rb +101 -0
  12. data/lib/active_support/refinements/core_ext/array/prepend_and_append.rb +9 -0
  13. data/lib/active_support/refinements/core_ext/array/uniq_by.rb +21 -0
  14. data/lib/active_support/refinements/core_ext/array/wrap.rb +48 -0
  15. data/lib/active_support/refinements/core_ext/benchmark.rb +7 -0
  16. data/lib/active_support/refinements/core_ext/big_decimal.rb +1 -0
  17. data/lib/active_support/refinements/core_ext/big_decimal/conversions.rb +32 -0
  18. data/lib/active_support/refinements/core_ext/class.rb +4 -0
  19. data/lib/active_support/refinements/core_ext/class/attribute.rb +119 -0
  20. data/lib/active_support/refinements/core_ext/class/attribute_accessors.rb +172 -0
  21. data/lib/active_support/refinements/core_ext/class/delegating_attributes.rb +42 -0
  22. data/lib/active_support/refinements/core_ext/class/subclasses.rb +44 -0
  23. data/lib/active_support/refinements/core_ext/date.rb +5 -0
  24. data/lib/active_support/refinements/core_ext/date/acts_like.rb +10 -0
  25. data/lib/active_support/refinements/core_ext/date/calculations.rb +123 -0
  26. data/lib/active_support/refinements/core_ext/date/conversions.rb +86 -0
  27. data/lib/active_support/refinements/core_ext/date/zones.rb +17 -0
  28. data/lib/active_support/refinements/core_ext/date_and_time/calculations.rb +232 -0
  29. data/lib/active_support/refinements/core_ext/date_time.rb +4 -0
  30. data/lib/active_support/refinements/core_ext/date_time/acts_like.rb +15 -0
  31. data/lib/active_support/refinements/core_ext/date_time/calculations.rb +143 -0
  32. data/lib/active_support/refinements/core_ext/date_time/conversions.rb +93 -0
  33. data/lib/active_support/refinements/core_ext/date_time/zones.rb +26 -0
  34. data/lib/active_support/refinements/core_ext/enumerable.rb +82 -0
  35. data/lib/active_support/refinements/core_ext/exception.rb +5 -0
  36. data/lib/active_support/refinements/core_ext/file.rb +1 -0
  37. data/lib/active_support/refinements/core_ext/file/atomic.rb +60 -0
  38. data/lib/active_support/refinements/core_ext/hash.rb +8 -0
  39. data/lib/active_support/refinements/core_ext/hash/conversions.rb +161 -0
  40. data/lib/active_support/refinements/core_ext/hash/deep_merge.rb +29 -0
  41. data/lib/active_support/refinements/core_ext/hash/diff.rb +15 -0
  42. data/lib/active_support/refinements/core_ext/hash/except.rb +17 -0
  43. data/lib/active_support/refinements/core_ext/hash/indifferent_access.rb +24 -0
  44. data/lib/active_support/refinements/core_ext/hash/keys.rb +140 -0
  45. data/lib/active_support/refinements/core_ext/hash/reverse_merge.rb +24 -0
  46. data/lib/active_support/refinements/core_ext/hash/slice.rb +42 -0
  47. data/lib/active_support/refinements/core_ext/integer.rb +3 -0
  48. data/lib/active_support/refinements/core_ext/integer/inflections.rb +31 -0
  49. data/lib/active_support/refinements/core_ext/integer/multiple.rb +12 -0
  50. data/lib/active_support/refinements/core_ext/integer/time.rb +43 -0
  51. data/lib/active_support/refinements/core_ext/kernel.rb +4 -0
  52. data/lib/active_support/refinements/core_ext/kernel/agnostics.rb +13 -0
  53. data/lib/active_support/refinements/core_ext/kernel/debugger.rb +12 -0
  54. data/lib/active_support/refinements/core_ext/kernel/reporting.rb +97 -0
  55. data/lib/active_support/refinements/core_ext/kernel/singleton_class.rb +8 -0
  56. data/lib/active_support/refinements/core_ext/load_error.rb +27 -0
  57. data/lib/active_support/refinements/core_ext/logger.rb +86 -0
  58. data/lib/active_support/refinements/core_ext/module.rb +10 -0
  59. data/lib/active_support/refinements/core_ext/module/aliasing.rb +69 -0
  60. data/lib/active_support/refinements/core_ext/module/anonymous.rb +21 -0
  61. data/lib/active_support/refinements/core_ext/module/attr_internal.rb +40 -0
  62. data/lib/active_support/refinements/core_ext/module/attribute_accessors.rb +68 -0
  63. data/lib/active_support/refinements/core_ext/module/delegation.rb +172 -0
  64. data/lib/active_support/refinements/core_ext/module/deprecation.rb +27 -0
  65. data/lib/active_support/refinements/core_ext/module/introspection.rb +80 -0
  66. data/lib/active_support/refinements/core_ext/module/qualified_const.rb +54 -0
  67. data/lib/active_support/refinements/core_ext/module/reachable.rb +10 -0
  68. data/lib/active_support/refinements/core_ext/module/remove_method.rb +14 -0
  69. data/lib/active_support/refinements/core_ext/name_error.rb +20 -0
  70. data/lib/active_support/refinements/core_ext/numeric.rb +3 -0
  71. data/lib/active_support/refinements/core_ext/numeric/bytes.rb +46 -0
  72. data/lib/active_support/refinements/core_ext/numeric/conversions.rb +137 -0
  73. data/lib/active_support/refinements/core_ext/numeric/time.rb +81 -0
  74. data/lib/active_support/refinements/core_ext/object.rb +14 -0
  75. data/lib/active_support/refinements/core_ext/object/acts_like.rb +12 -0
  76. data/lib/active_support/refinements/core_ext/object/blank.rb +107 -0
  77. data/lib/active_support/refinements/core_ext/object/conversions.rb +4 -0
  78. data/lib/active_support/refinements/core_ext/object/deep_dup.rb +48 -0
  79. data/lib/active_support/refinements/core_ext/object/duplicable.rb +92 -0
  80. data/lib/active_support/refinements/core_ext/object/inclusion.rb +27 -0
  81. data/lib/active_support/refinements/core_ext/object/instance_variables.rb +30 -0
  82. data/lib/active_support/refinements/core_ext/object/to_json.rb +27 -0
  83. data/lib/active_support/refinements/core_ext/object/to_param.rb +60 -0
  84. data/lib/active_support/refinements/core_ext/object/to_query.rb +29 -0
  85. data/lib/active_support/refinements/core_ext/object/try.rb +72 -0
  86. data/lib/active_support/refinements/core_ext/object/with_options.rb +44 -0
  87. data/lib/active_support/refinements/core_ext/proc.rb +19 -0
  88. data/lib/active_support/refinements/core_ext/range.rb +3 -0
  89. data/lib/active_support/refinements/core_ext/range/conversions.rb +21 -0
  90. data/lib/active_support/refinements/core_ext/range/include_range.rb +23 -0
  91. data/lib/active_support/refinements/core_ext/range/overlaps.rb +10 -0
  92. data/lib/active_support/refinements/core_ext/regexp.rb +7 -0
  93. data/lib/active_support/refinements/core_ext/string.rb +13 -0
  94. data/lib/active_support/refinements/core_ext/string/access.rb +106 -0
  95. data/lib/active_support/refinements/core_ext/string/behavior.rb +8 -0
  96. data/lib/active_support/refinements/core_ext/string/conversions.rb +60 -0
  97. data/lib/active_support/refinements/core_ext/string/encoding.rb +10 -0
  98. data/lib/active_support/refinements/core_ext/string/exclude.rb +13 -0
  99. data/lib/active_support/refinements/core_ext/string/filters.rb +54 -0
  100. data/lib/active_support/refinements/core_ext/string/indent.rb +45 -0
  101. data/lib/active_support/refinements/core_ext/string/inflections.rb +214 -0
  102. data/lib/active_support/refinements/core_ext/string/inquiry.rb +15 -0
  103. data/lib/active_support/refinements/core_ext/string/multibyte.rb +58 -0
  104. data/lib/active_support/refinements/core_ext/string/output_safety.rb +194 -0
  105. data/lib/active_support/refinements/core_ext/string/starts_ends_with.rb +6 -0
  106. data/lib/active_support/refinements/core_ext/string/strip.rb +28 -0
  107. data/lib/active_support/refinements/core_ext/string/xchar.rb +18 -0
  108. data/lib/active_support/refinements/core_ext/time.rb +5 -0
  109. data/lib/active_support/refinements/core_ext/time/acts_like.rb +10 -0
  110. data/lib/active_support/refinements/core_ext/time/calculations.rb +251 -0
  111. data/lib/active_support/refinements/core_ext/time/conversions.rb +65 -0
  112. data/lib/active_support/refinements/core_ext/time/marshal.rb +30 -0
  113. data/lib/active_support/refinements/core_ext/time/zones.rb +98 -0
  114. data/lib/active_support/refinements/core_ext/uri.rb +28 -0
  115. data/lib/activesupport-refinements.rb +9 -0
  116. data/lib/activesupport-refinements/version.rb +5 -0
  117. data/refine_core_ext.rb +45 -0
  118. data/spec/hwia_spec.rb +15 -0
  119. data/spec/try_spec.rb +18 -0
  120. metadata +182 -0
@@ -0,0 +1,3 @@
1
+ require 'active_support/refinements/core_ext/range/conversions'
2
+ require 'active_support/refinements/core_ext/range/include_range'
3
+ require 'active_support/refinements/core_ext/range/overlaps'
@@ -0,0 +1,21 @@
1
+ module RangeExt; end; module RangeExt::Conversions
2
+ refine Range do
3
+ RANGE_FORMATS = {
4
+ :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
5
+ }
6
+
7
+ # Gives a human readable format of the range.
8
+ #
9
+ # (1..100).to_formatted_s # => "1..100"
10
+ def to_formatted_s(format = :default)
11
+ if formatter = RANGE_FORMATS[format]
12
+ formatter.call(first, last)
13
+ else
14
+ to_default_s
15
+ end
16
+ end
17
+
18
+ # alias_method :to_default_s, :to_s
19
+ # alias_method :to_s, :to_formatted_s
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ module RangeExt; end; module RangeExt::IncludeRange
2
+ refine Range do
3
+ # Extends the default Range#include? to support range comparisons.
4
+ # (1..5).include?(1..5) # => true
5
+ # (1..5).include?(2..3) # => true
6
+ # (1..5).include?(2..6) # => false
7
+ #
8
+ # The native Range#include? behavior is untouched.
9
+ # ('a'..'f').include?('c') # => true
10
+ # (5..9).include?(11) # => false
11
+ def include_with_range?(value)
12
+ if value.is_a?(::Range)
13
+ # 1...10 includes 1..9 but it does not include 1..10.
14
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
15
+ include_without_range?(value.first) && value.last.send(operator, last)
16
+ else
17
+ include_without_range?(value)
18
+ end
19
+ end
20
+
21
+ # alias_method_chain :include?, :range
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ module RangeExt; end; module RangeExt::Overlaps
2
+ refine Range do
3
+ # Compare two ranges and see if they overlap each other
4
+ # (1..5).overlaps?(4..6) # => true
5
+ # (1..5).overlaps?(7..9) # => false
6
+ def overlaps?(other)
7
+ cover?(other.first) || other.cover?(first)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module RegexpExt
2
+ refine Regexp do
3
+ def multiline?
4
+ options & MULTILINE == MULTILINE
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ require 'active_support/refinements/core_ext/string/conversions'
2
+ require 'active_support/refinements/core_ext/string/filters'
3
+ require 'active_support/refinements/core_ext/string/multibyte'
4
+ require 'active_support/refinements/core_ext/string/starts_ends_with'
5
+ require 'active_support/refinements/core_ext/string/inflections'
6
+ require 'active_support/refinements/core_ext/string/access'
7
+ require 'active_support/refinements/core_ext/string/xchar'
8
+ require 'active_support/refinements/core_ext/string/behavior'
9
+ require 'active_support/refinements/core_ext/string/output_safety'
10
+ require 'active_support/refinements/core_ext/string/exclude'
11
+ require 'active_support/refinements/core_ext/string/strip'
12
+ require 'active_support/refinements/core_ext/string/inquiry'
13
+ require 'active_support/refinements/core_ext/string/indent'
@@ -0,0 +1,106 @@
1
+ module StringExt; end; module StringExt::Access
2
+ refine String do
3
+ # If you pass a single Fixnum, returns a substring of one character at that
4
+ # position. The first character of the string is at position 0, the next at
5
+ # position 1, and so on. If a range is supplied, a substring containing
6
+ # characters at offsets given by the range is returned. In both cases, if an
7
+ # offset is negative, it is counted from the end of the string. Returns nil
8
+ # if the initial offset falls outside the string. Returns an empty string if
9
+ # the beginning of the range is greater than the end of the string.
10
+ #
11
+ # str = "hello"
12
+ # str.at(0) #=> "h"
13
+ # str.at(1..3) #=> "ell"
14
+ # str.at(-2) #=> "l"
15
+ # str.at(-2..-1) #=> "lo"
16
+ # str.at(5) #=> nil
17
+ # str.at(5..-1) #=> ""
18
+ #
19
+ # If a Regexp is given, the matching portion of the string is returned.
20
+ # If a String is given, that given string is returned if it occurs in
21
+ # the string. In both cases, nil is returned if there is no match.
22
+ #
23
+ # str = "hello"
24
+ # str.at(/lo/) #=> "lo"
25
+ # str.at(/ol/) #=> nil
26
+ # str.at("lo") #=> "lo"
27
+ # str.at("ol") #=> nil
28
+ def at(position)
29
+ self[position]
30
+ end
31
+
32
+ # Returns a substring from the given position to the end of the string.
33
+ # If the position is negative, it is counted from the end of the string.
34
+ #
35
+ # str = "hello"
36
+ # str.from(0) #=> "hello"
37
+ # str.from(3) #=> "lo"
38
+ # str.from(-2) #=> "lo"
39
+ #
40
+ # You can mix it with +to+ method and do fun things like:
41
+ #
42
+ # str = "hello"
43
+ # str.from(0).to(-1) #=> "hello"
44
+ # str.from(1).to(-2) #=> "ell"
45
+ def from(position)
46
+ self[position..-1]
47
+ end
48
+
49
+ # Returns a substring from the beginning of the string to the given position.
50
+ # If the position is negative, it is counted from the end of the string.
51
+ #
52
+ # str = "hello"
53
+ # str.to(0) #=> "h"
54
+ # str.to(3) #=> "hell"
55
+ # str.to(-2) #=> "hell"
56
+ #
57
+ # You can mix it with +from+ method and do fun things like:
58
+ #
59
+ # str = "hello"
60
+ # str.from(0).to(-1) #=> "hello"
61
+ # str.from(1).to(-2) #=> "ell"
62
+ def to(position)
63
+ self[0..position]
64
+ end
65
+
66
+ # Returns the first character. If a limit is supplied, returns a substring
67
+ # from the beginning of the string until it reaches the limit value. If the
68
+ # given limit is greater than or equal to the string length, returns self.
69
+ #
70
+ # str = "hello"
71
+ # str.first #=> "h"
72
+ # str.first(1) #=> "h"
73
+ # str.first(2) #=> "he"
74
+ # str.first(0) #=> ""
75
+ # str.first(6) #=> "hello"
76
+ def first(limit = 1)
77
+ if limit == 0
78
+ ''
79
+ elsif limit >= size
80
+ self
81
+ else
82
+ to(limit - 1)
83
+ end
84
+ end
85
+
86
+ # Returns the last character of the string. If a limit is supplied, returns a substring
87
+ # from the end of the string until it reaches the limit value (counting backwards). If
88
+ # the given limit is greater than or equal to the string length, returns self.
89
+ #
90
+ # str = "hello"
91
+ # str.last #=> "o"
92
+ # str.last(1) #=> "o"
93
+ # str.last(2) #=> "lo"
94
+ # str.last(0) #=> ""
95
+ # str.last(6) #=> "hello"
96
+ def last(limit = 1)
97
+ if limit == 0
98
+ ''
99
+ elsif limit >= size
100
+ self
101
+ else
102
+ from(-limit)
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,8 @@
1
+ module StringExt; end; module StringExt::Behavior
2
+ refine String do
3
+ # Enable more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
4
+ def acts_like_string?
5
+ true
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,60 @@
1
+ module StringExt; end; module StringExt::Conversions
2
+ require 'date'
3
+ require 'active_support/refinements/core_ext/time/calculations'
4
+
5
+ refine String do
6
+ # Converts a string to a Time value.
7
+ # The +form+ can be either :utc or :local (default :utc).
8
+ #
9
+ # The time is parsed using Date._parse method.
10
+ # If +form+ is :local, then time is formatted using Time.zone
11
+ #
12
+ # "3-2-2012".to_time # => 2012-02-03 00:00:00 UTC
13
+ # "12:20".to_time # => ArgumentError: invalid date
14
+ # "2012-12-13 06:12".to_time # => 2012-12-13 06:12:00 UTC
15
+ # "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 UTC
16
+ # "2012-12-13T06:12".to_time(:local) # => 2012-12-13 06:12:00 +0100
17
+ def to_time(form = :utc)
18
+ unless blank?
19
+ date_values = ::Date._parse(self, false).
20
+ values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset).
21
+ map! { |arg| arg || 0 }
22
+ date_values[6] *= 1000000
23
+ offset = date_values.pop
24
+
25
+ ::Time.send("#{form}_time", *date_values) - offset
26
+ end
27
+ end
28
+
29
+ # Converts a string to a Date value.
30
+ #
31
+ # "1-1-2012".to_date #=> Sun, 01 Jan 2012
32
+ # "01/01/2012".to_date #=> Sun, 01 Jan 2012
33
+ # "2012-12-13".to_date #=> Thu, 13 Dec 2012
34
+ # "12/13/2012".to_date #=> ArgumentError: invalid date
35
+ def to_date
36
+ unless blank?
37
+ date_values = ::Date._parse(self, false).values_at(:year, :mon, :mday)
38
+
39
+ ::Date.new(*date_values)
40
+ end
41
+ end
42
+
43
+ # Converts a string to a DateTime value.
44
+ #
45
+ # "1-1-2012".to_datetime #=> Sun, 01 Jan 2012 00:00:00 +0000
46
+ # "01/01/2012 23:59:59".to_datetime #=> Sun, 01 Jan 2012 23:59:59 +0000
47
+ # "2012-12-13 12:50".to_datetime #=> Thu, 13 Dec 2012 12:50:00 +0000
48
+ # "12/13/2012".to_datetime #=> ArgumentError: invalid date
49
+ def to_datetime
50
+ unless blank?
51
+ date_values = ::Date._parse(self, false).
52
+ values_at(:year, :mon, :mday, :hour, :min, :sec, :zone, :sec_fraction).
53
+ map! { |arg| arg || 0 }
54
+ date_values[5] += date_values.pop
55
+
56
+ ::DateTime.civil(*date_values)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,10 @@
1
+ module StringExt; end; module StringExt::Encoding
2
+ require 'active_support/deprecation'
3
+
4
+ refine String do
5
+ def encoding_aware?
6
+ ActiveSupport::Deprecation.warn 'String#encoding_aware? is deprecated', caller
7
+ true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module StringExt; end; module StringExt::Exclude
2
+ refine String do
3
+ # The inverse of <tt>String#include?</tt>. Returns true if the string
4
+ # does not include the other string.
5
+ #
6
+ # "hello".exclude? "lo" #=> false
7
+ # "hello".exclude? "ol" #=> true
8
+ # "hello".exclude? ?h #=> false
9
+ def exclude?(string)
10
+ !include?(string)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,54 @@
1
+ module StringExt; end; module StringExt::Filters
2
+ refine String do
3
+ # Returns the string, first removing all whitespace on both ends of
4
+ # the string, and then changing remaining consecutive whitespace
5
+ # groups into one space each.
6
+ #
7
+ # %{ Multi-line
8
+ # string }.squish # => "Multi-line string"
9
+ # " foo bar \n \t boo".squish # => "foo bar boo"
10
+ def squish
11
+ dup.squish!
12
+ end
13
+
14
+ # Performs a destructive squish. See String#squish.
15
+ def squish!
16
+ strip!
17
+ gsub!(/\s+/, ' ')
18
+ self
19
+ end
20
+
21
+ # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
22
+ #
23
+ # 'Once upon a time in a world far far away'.truncate(27)
24
+ # # => "Once upon a time in a wo..."
25
+ #
26
+ # Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
27
+ #
28
+ # 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
29
+ # # => "Once upon a time in a..."
30
+ #
31
+ # 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
32
+ # # => "Once upon a time in a..."
33
+ #
34
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
35
+ # for a total length not exceeding <tt>length</tt>:
36
+ #
37
+ # 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
38
+ # # => "And they f... (continued)"
39
+ def truncate(truncate_at, options = {})
40
+ return dup unless length > truncate_at
41
+
42
+ options[:omission] ||= '...'
43
+ length_with_room_for_omission = truncate_at - options[:omission].length
44
+ stop = \
45
+ if options[:separator]
46
+ rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
47
+ else
48
+ length_with_room_for_omission
49
+ end
50
+
51
+ self[0...stop] + options[:omission]
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,45 @@
1
+ module StringExt; end; module StringExt::Indent
2
+ refine String do
3
+ # Same as +indent+, except it indents the receiver in-place.
4
+ #
5
+ # Returns the indented string, or +nil+ if there was nothing to indent.
6
+ def indent!(amount, indent_string=nil, indent_empty_lines=false)
7
+ indent_string = indent_string || self[/^[ \t]/] || ' '
8
+ re = indent_empty_lines ? /^/ : /^(?!$)/
9
+ gsub!(re, indent_string * amount)
10
+ end
11
+
12
+ # Indents the lines in the receiver:
13
+ #
14
+ # <<EOS.indent(2)
15
+ # def some_method
16
+ # some_code
17
+ # end
18
+ # EOS
19
+ # # =>
20
+ # def some_method
21
+ # some_code
22
+ # end
23
+ #
24
+ # The second argument, +indent_string+, specifies which indent string to
25
+ # use. The default is +nil+, which tells the method to make a guess by
26
+ # peeking at the first indented line, and fallback to a space if there is
27
+ # none.
28
+ #
29
+ # " foo".indent(2) # => " foo"
30
+ # "foo\n\t\tbar".indent(2) # => "\t\tfoo\n\t\t\t\tbar"
31
+ # "foo".indent(2, "\t") # => "\t\tfoo"
32
+ #
33
+ # While +indent_string+ is tipically one space or tab, it may be any string.
34
+ #
35
+ # The third argument, +indent_empty_lines+, is a flag that says whether
36
+ # empty lines should be indented. Default is false.
37
+ #
38
+ # "foo\n\nbar".indent(2) # => " foo\n\n bar"
39
+ # "foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar"
40
+ #
41
+ def indent(amount, indent_string=nil, indent_empty_lines=false)
42
+ dup.tap {|_| _.indent!(amount, indent_string, indent_empty_lines)}
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,214 @@
1
+ module StringExt; end; module StringExt::Inflections
2
+ require 'active_support/inflector/methods'
3
+ require 'active_support/inflector/transliterate'
4
+
5
+ # String inflections define new methods on the String class to transform names for different purposes.
6
+ # For instance, you can figure out the name of a table from the name of a class.
7
+ #
8
+ # 'ScaleScore'.tableize # => "scale_scores"
9
+ #
10
+ refine String do
11
+ # Returns the plural form of the word in the string.
12
+ #
13
+ # If the optional parameter +count+ is specified,
14
+ # the singular form will be returned if <tt>count == 1</tt>.
15
+ # For any other value of +count+ the plural will be returned.
16
+ #
17
+ # If the optional parameter +locale+ is specified,
18
+ # the word will be pluralized as a word of that language.
19
+ # By default, this parameter is set to <tt>:en</tt>.
20
+ # You must define your own inflection rules for languages other than English.
21
+ #
22
+ # 'post'.pluralize # => "posts"
23
+ # 'octopus'.pluralize # => "octopi"
24
+ # 'sheep'.pluralize # => "sheep"
25
+ # 'words'.pluralize # => "words"
26
+ # 'the blue mailman'.pluralize # => "the blue mailmen"
27
+ # 'CamelOctopus'.pluralize # => "CamelOctopi"
28
+ # 'apple'.pluralize(1) # => "apple"
29
+ # 'apple'.pluralize(2) # => "apples"
30
+ # 'ley'.pluralize(:es) # => "leyes"
31
+ # 'ley'.pluralize(1, :es) # => "ley"
32
+ def pluralize(count = nil, locale = :en)
33
+ locale = count if count.is_a?(Symbol)
34
+ if count == 1
35
+ self
36
+ else
37
+ ActiveSupport::Inflector.pluralize(self, locale)
38
+ end
39
+ end
40
+
41
+ # The reverse of +pluralize+, returns the singular form of a word in a string.
42
+ #
43
+ # If the optional parameter +locale+ is specified,
44
+ # the word will be singularized as a word of that language.
45
+ # By default, this paramter is set to <tt>:en</tt>.
46
+ # You must define your own inflection rules for languages other than English.
47
+ #
48
+ # 'posts'.singularize # => "post"
49
+ # 'octopi'.singularize # => "octopus"
50
+ # 'sheep'.singularize # => "sheep"
51
+ # 'word'.singularize # => "word"
52
+ # 'the blue mailmen'.singularize # => "the blue mailman"
53
+ # 'CamelOctopi'.singularize # => "CamelOctopus"
54
+ # 'leyes'.singularize(:es) # => "ley"
55
+ def singularize(locale = :en)
56
+ ActiveSupport::Inflector.singularize(self, locale)
57
+ end
58
+
59
+ # +constantize+ tries to find a declared constant with the name specified
60
+ # in the string. It raises a NameError when the name is not in CamelCase
61
+ # or is not initialized. See ActiveSupport::Inflector.constantize
62
+ #
63
+ # 'Module'.constantize # => Module
64
+ # 'Class'.constantize # => Class
65
+ # 'blargle'.constantize # => NameError: wrong constant name blargle
66
+ def constantize
67
+ ActiveSupport::Inflector.constantize(self)
68
+ end
69
+
70
+ # +safe_constantize+ tries to find a declared constant with the name specified
71
+ # in the string. It returns nil when the name is not in CamelCase
72
+ # or is not initialized. See ActiveSupport::Inflector.safe_constantize
73
+ #
74
+ # 'Module'.safe_constantize # => Module
75
+ # 'Class'.safe_constantize # => Class
76
+ # 'blargle'.safe_constantize # => nil
77
+ def safe_constantize
78
+ ActiveSupport::Inflector.safe_constantize(self)
79
+ end
80
+
81
+ # By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
82
+ # is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
83
+ #
84
+ # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
85
+ #
86
+ # 'active_record'.camelize # => "ActiveRecord"
87
+ # 'active_record'.camelize(:lower) # => "activeRecord"
88
+ # 'active_record/errors'.camelize # => "ActiveRecord::Errors"
89
+ # 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
90
+ def camelize(first_letter = :upper)
91
+ case first_letter
92
+ when :upper
93
+ ActiveSupport::Inflector.camelize(self, true)
94
+ when :lower
95
+ ActiveSupport::Inflector.camelize(self, false)
96
+ end
97
+ end
98
+ # alias_method :camelcase, :camelize
99
+
100
+ # Capitalizes all the words and replaces some characters in the string to create
101
+ # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
102
+ # used in the Rails internals.
103
+ #
104
+ # +titleize+ is also aliased as +titlecase+.
105
+ #
106
+ # 'man from the boondocks'.titleize # => "Man From The Boondocks"
107
+ # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
108
+ def titleize
109
+ ActiveSupport::Inflector.titleize(self)
110
+ end
111
+ # alias_method :titlecase, :titleize
112
+
113
+ # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
114
+ #
115
+ # +underscore+ will also change '::' to '/' to convert namespaces to paths.
116
+ #
117
+ # 'ActiveModel'.underscore # => "active_model"
118
+ # 'ActiveModel::Errors'.underscore # => "active_model/errors"
119
+ def underscore
120
+ ActiveSupport::Inflector.underscore(self)
121
+ end
122
+
123
+ # Replaces underscores with dashes in the string.
124
+ #
125
+ # 'puni_puni'.dasherize # => "puni-puni"
126
+ def dasherize
127
+ ActiveSupport::Inflector.dasherize(self)
128
+ end
129
+
130
+ # Removes the module part from the constant expression in the string.
131
+ #
132
+ # 'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections"
133
+ # 'Inflections'.demodulize # => "Inflections"
134
+ #
135
+ # See also +deconstantize+.
136
+ def demodulize
137
+ ActiveSupport::Inflector.demodulize(self)
138
+ end
139
+
140
+ # Removes the rightmost segment from the constant expression in the string.
141
+ #
142
+ # 'Net::HTTP'.deconstantize # => "Net"
143
+ # '::Net::HTTP'.deconstantize # => "::Net"
144
+ # 'String'.deconstantize # => ""
145
+ # '::String'.deconstantize # => ""
146
+ # ''.deconstantize # => ""
147
+ #
148
+ # See also +demodulize+.
149
+ def deconstantize
150
+ ActiveSupport::Inflector.deconstantize(self)
151
+ end
152
+
153
+ # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
154
+ #
155
+ # class Person
156
+ # def to_param
157
+ # "#{id}-#{name.parameterize}"
158
+ # end
159
+ # end
160
+ #
161
+ # @person = Person.find(1)
162
+ # # => #<Person id: 1, name: "Donald E. Knuth">
163
+ #
164
+ # <%= link_to(@person.name, person_path %>
165
+ # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
166
+ def parameterize(sep = '-')
167
+ ActiveSupport::Inflector.parameterize(self, sep)
168
+ end
169
+
170
+ # Creates the name of a table like Rails does for models to table names. This method
171
+ # uses the +pluralize+ method on the last word in the string.
172
+ #
173
+ # 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
174
+ # 'egg_and_ham'.tableize # => "egg_and_hams"
175
+ # 'fancyCategory'.tableize # => "fancy_categories"
176
+ def tableize
177
+ ActiveSupport::Inflector.tableize(self)
178
+ end
179
+
180
+ # Create a class name from a plural table name like Rails does for table names to models.
181
+ # Note that this returns a string and not a class. (To convert to an actual class
182
+ # follow +classify+ with +constantize+.)
183
+ #
184
+ # 'egg_and_hams'.classify # => "EggAndHam"
185
+ # 'posts'.classify # => "Post"
186
+ #
187
+ # Singular names are not handled correctly.
188
+ #
189
+ # 'business'.classify # => "Busines"
190
+ def classify
191
+ ActiveSupport::Inflector.classify(self)
192
+ end
193
+
194
+ # Capitalizes the first word, turns underscores into spaces, and strips '_id'.
195
+ # Like +titleize+, this is meant for creating pretty output.
196
+ #
197
+ # 'employee_salary' # => "Employee salary"
198
+ # 'author_id' # => "Author"
199
+ def humanize
200
+ ActiveSupport::Inflector.humanize(self)
201
+ end
202
+
203
+ # Creates a foreign key name from a class name.
204
+ # +separate_class_name_and_id_with_underscore+ sets whether
205
+ # the method should put '_' between the name and 'id'.
206
+ #
207
+ # 'Message'.foreign_key # => "message_id"
208
+ # 'Message'.foreign_key(false) # => "messageid"
209
+ # 'Admin::Post'.foreign_key # => "post_id"
210
+ def foreign_key(separate_class_name_and_id_with_underscore = true)
211
+ ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
212
+ end
213
+ end
214
+ end