sigterm_extensions 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +17 -0
  3. data/Gemfile +6 -0
  4. data/LICENSE.md +0 -0
  5. data/README.md +0 -0
  6. data/bin/ctxirb +156 -0
  7. data/lib/git.rb +166 -0
  8. data/lib/git/LICENSE +21 -0
  9. data/lib/git/author.rb +14 -0
  10. data/lib/git/base.rb +551 -0
  11. data/lib/git/base/factory.rb +75 -0
  12. data/lib/git/branch.rb +126 -0
  13. data/lib/git/branches.rb +71 -0
  14. data/lib/git/config.rb +22 -0
  15. data/lib/git/diff.rb +159 -0
  16. data/lib/git/index.rb +5 -0
  17. data/lib/git/lib.rb +1041 -0
  18. data/lib/git/log.rb +128 -0
  19. data/lib/git/object.rb +312 -0
  20. data/lib/git/path.rb +31 -0
  21. data/lib/git/remote.rb +36 -0
  22. data/lib/git/repository.rb +6 -0
  23. data/lib/git/stash.rb +27 -0
  24. data/lib/git/stashes.rb +55 -0
  25. data/lib/git/status.rb +199 -0
  26. data/lib/git/version.rb +5 -0
  27. data/lib/git/working_directory.rb +4 -0
  28. data/lib/sigterm_extensions.rb +75 -0
  29. data/lib/sigterm_extensions/all.rb +12 -0
  30. data/lib/sigterm_extensions/backtrace_cleaner.rb +129 -0
  31. data/lib/sigterm_extensions/callbacks.rb +847 -0
  32. data/lib/sigterm_extensions/concern.rb +169 -0
  33. data/lib/sigterm_extensions/configurable.rb +38 -0
  34. data/lib/sigterm_extensions/core_ext.rb +4 -0
  35. data/lib/sigterm_extensions/core_ext/array.rb +3 -0
  36. data/lib/sigterm_extensions/core_ext/array/extract.rb +19 -0
  37. data/lib/sigterm_extensions/core_ext/array/extract_options.rb +29 -0
  38. data/lib/sigterm_extensions/core_ext/class.rb +3 -0
  39. data/lib/sigterm_extensions/core_ext/class/attribute.rb +139 -0
  40. data/lib/sigterm_extensions/core_ext/class/attribute_accessors.rb +4 -0
  41. data/lib/sigterm_extensions/core_ext/class/subclasses.rb +52 -0
  42. data/lib/sigterm_extensions/core_ext/custom.rb +12 -0
  43. data/lib/sigterm_extensions/core_ext/digest.rb +3 -0
  44. data/lib/sigterm_extensions/core_ext/digest/uuid.rb +51 -0
  45. data/lib/sigterm_extensions/core_ext/enumerable.rb +232 -0
  46. data/lib/sigterm_extensions/core_ext/file.rb +3 -0
  47. data/lib/sigterm_extensions/core_ext/file/atomic.rb +68 -0
  48. data/lib/sigterm_extensions/core_ext/hash.rb +3 -0
  49. data/lib/sigterm_extensions/core_ext/hash/deep_merge.rb +41 -0
  50. data/lib/sigterm_extensions/core_ext/hash/deep_transform_values.rb +44 -0
  51. data/lib/sigterm_extensions/core_ext/hash/except.rb +22 -0
  52. data/lib/sigterm_extensions/core_ext/hash/keys.rb +141 -0
  53. data/lib/sigterm_extensions/core_ext/hash/reverse_merge.rb +23 -0
  54. data/lib/sigterm_extensions/core_ext/hash/slice.rb +24 -0
  55. data/lib/sigterm_extensions/core_ext/kernel.rb +3 -0
  56. data/lib/sigterm_extensions/core_ext/kernel/concern.rb +12 -0
  57. data/lib/sigterm_extensions/core_ext/kernel/reporting.rb +43 -0
  58. data/lib/sigterm_extensions/core_ext/kernel/singleton_class.rb +6 -0
  59. data/lib/sigterm_extensions/core_ext/load_error.rb +7 -0
  60. data/lib/sigterm_extensions/core_ext/module.rb +3 -0
  61. data/lib/sigterm_extensions/core_ext/module/aliasing.rb +29 -0
  62. data/lib/sigterm_extensions/core_ext/module/anonymous.rb +28 -0
  63. data/lib/sigterm_extensions/core_ext/module/attr_internal.rb +36 -0
  64. data/lib/sigterm_extensions/core_ext/module/attribute_accessors.rb +208 -0
  65. data/lib/sigterm_extensions/core_ext/module/attribute_accessors_per_thread.rb +146 -0
  66. data/lib/sigterm_extensions/core_ext/module/concerning.rb +132 -0
  67. data/lib/sigterm_extensions/core_ext/module/delegation.rb +319 -0
  68. data/lib/sigterm_extensions/core_ext/module/redefine_method.rb +38 -0
  69. data/lib/sigterm_extensions/core_ext/module/remove_method.rb +15 -0
  70. data/lib/sigterm_extensions/core_ext/name_error.rb +36 -0
  71. data/lib/sigterm_extensions/core_ext/object.rb +3 -0
  72. data/lib/sigterm_extensions/core_ext/object/blank.rb +153 -0
  73. data/lib/sigterm_extensions/core_ext/object/colors.rb +39 -0
  74. data/lib/sigterm_extensions/core_ext/object/duplicable.rb +47 -0
  75. data/lib/sigterm_extensions/core_ext/object/inclusion.rb +27 -0
  76. data/lib/sigterm_extensions/core_ext/object/instance_variables.rb +28 -0
  77. data/lib/sigterm_extensions/core_ext/object/methods.rb +61 -0
  78. data/lib/sigterm_extensions/core_ext/object/with_options.rb +80 -0
  79. data/lib/sigterm_extensions/core_ext/range.rb +3 -0
  80. data/lib/sigterm_extensions/core_ext/range/compare_range.rb +74 -0
  81. data/lib/sigterm_extensions/core_ext/range/conversions.rb +39 -0
  82. data/lib/sigterm_extensions/core_ext/range/overlaps.rb +8 -0
  83. data/lib/sigterm_extensions/core_ext/securerandom.rb +43 -0
  84. data/lib/sigterm_extensions/core_ext/string.rb +3 -0
  85. data/lib/sigterm_extensions/core_ext/string/access.rb +93 -0
  86. data/lib/sigterm_extensions/core_ext/string/filters.rb +143 -0
  87. data/lib/sigterm_extensions/core_ext/string/starts_ends_with.rb +4 -0
  88. data/lib/sigterm_extensions/core_ext/string/strip.rb +25 -0
  89. data/lib/sigterm_extensions/core_ext/tryable.rb +132 -0
  90. data/lib/sigterm_extensions/descendants_tracker.rb +108 -0
  91. data/lib/sigterm_extensions/gem_methods.rb +47 -0
  92. data/lib/sigterm_extensions/hash_binding.rb +16 -0
  93. data/lib/sigterm_extensions/inflector.rb +339 -0
  94. data/lib/sigterm_extensions/inflector/acronyms.rb +42 -0
  95. data/lib/sigterm_extensions/inflector/inflections.rb +249 -0
  96. data/lib/sigterm_extensions/inflector/inflections/defaults.rb +117 -0
  97. data/lib/sigterm_extensions/inflector/rules.rb +37 -0
  98. data/lib/sigterm_extensions/inflector/version.rb +8 -0
  99. data/lib/sigterm_extensions/interactive_editor.rb +120 -0
  100. data/lib/sigterm_extensions/lazy.rb +34 -0
  101. data/lib/sigterm_extensions/lazy_load_hooks.rb +79 -0
  102. data/lib/sigterm_extensions/option_merger.rb +32 -0
  103. data/lib/sigterm_extensions/ordered_hash.rb +48 -0
  104. data/lib/sigterm_extensions/ordered_options.rb +83 -0
  105. data/lib/sigterm_extensions/paths.rb +235 -0
  106. data/lib/sigterm_extensions/per_thread_registry.rb +58 -0
  107. data/lib/sigterm_extensions/proxy_object.rb +14 -0
  108. data/lib/sigterm_extensions/staging/boot.rb +31 -0
  109. data/lib/sigterm_extensions/staging/boot/bundler_patch.rb +24 -0
  110. data/lib/sigterm_extensions/staging/boot/command.rb +26 -0
  111. data/lib/sigterm_extensions/staging/boot/gemfile_next_auto_sync.rb +79 -0
  112. data/lib/sigterm_extensions/version.rb +4 -0
  113. data/lib/sigterm_extensions/wrappable.rb +16 -0
  114. data/sigterm_extensions.gemspec +42 -0
  115. data/templates/dotpryrc.rb.erb +124 -0
  116. metadata +315 -0
@@ -0,0 +1,4 @@
1
+ class String
2
+ alias_method :starts_with?, :start_with?
3
+ alias_method :ends_with?, :end_with?
4
+ end
@@ -0,0 +1,25 @@
1
+ class String
2
+ # Strips indentation in heredocs.
3
+ #
4
+ # For example in
5
+ #
6
+ # if options[:usage]
7
+ # puts <<-USAGE.strip_heredoc
8
+ # This command does such and such.
9
+ #
10
+ # Supported options are:
11
+ # -h This message
12
+ # ...
13
+ # USAGE
14
+ # end
15
+ #
16
+ # the user would see the usage message aligned against the left margin.
17
+ #
18
+ # Technically, it looks for the least indented non-empty line
19
+ # in the whole string, and removes that amount of leading whitespace.
20
+ def strip_heredoc
21
+ gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "").tap do |stripped|
22
+ stripped.freeze if frozen?
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,132 @@
1
+ module ActiveSupport
2
+ module Tryable #:nodoc:
3
+ def try(method_name = nil, *args, &b)
4
+ if method_name.nil? && block_given?
5
+ if b.arity == 0
6
+ instance_eval(&b)
7
+ else
8
+ yield self
9
+ end
10
+ elsif respond_to?(method_name)
11
+ public_send(method_name, *args, &b)
12
+ end
13
+ end
14
+
15
+ def try!(method_name = nil, *args, &b)
16
+ if method_name.nil? && block_given?
17
+ if b.arity == 0
18
+ instance_eval(&b)
19
+ else
20
+ yield self
21
+ end
22
+ else
23
+ public_send(method_name, *args, &b)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ class Object
30
+ include ActiveSupport::Tryable
31
+ ##
32
+ # :method: try
33
+ #
34
+ # :call-seq:
35
+ # try(*a, &b)
36
+ #
37
+ # Invokes the public method whose name goes as first argument just like
38
+ # +public_send+ does, except that if the receiver does not respond to it the
39
+ # call returns +nil+ rather than raising an exception.
40
+ #
41
+ # This method is defined to be able to write
42
+ #
43
+ # @person.try(:name)
44
+ #
45
+ # instead of
46
+ #
47
+ # @person.name if @person
48
+ #
49
+ # +try+ calls can be chained:
50
+ #
51
+ # @person.try(:spouse).try(:name)
52
+ #
53
+ # instead of
54
+ #
55
+ # @person.spouse.name if @person && @person.spouse
56
+ #
57
+ # +try+ will also return +nil+ if the receiver does not respond to the method:
58
+ #
59
+ # @person.try(:non_existing_method) # => nil
60
+ #
61
+ # instead of
62
+ #
63
+ # @person.non_existing_method if @person.respond_to?(:non_existing_method) # => nil
64
+ #
65
+ # +try+ returns +nil+ when called on +nil+ regardless of whether it responds
66
+ # to the method:
67
+ #
68
+ # nil.try(:to_i) # => nil, rather than 0
69
+ #
70
+ # Arguments and blocks are forwarded to the method if invoked:
71
+ #
72
+ # @posts.try(:each_slice, 2) do |a, b|
73
+ # ...
74
+ # end
75
+ #
76
+ # The number of arguments in the signature must match. If the object responds
77
+ # to the method the call is attempted and +ArgumentError+ is still raised
78
+ # in case of argument mismatch.
79
+ #
80
+ # If +try+ is called without arguments it yields the receiver to a given
81
+ # block unless it is +nil+:
82
+ #
83
+ # @person.try do |p|
84
+ # ...
85
+ # end
86
+ #
87
+ # You can also call try with a block without accepting an argument, and the block
88
+ # will be instance_eval'ed instead:
89
+ #
90
+ # @person.try { upcase.truncate(50) }
91
+ #
92
+ # Please also note that +try+ is defined on +Object+. Therefore, it won't work
93
+ # with instances of classes that do not have +Object+ among their ancestors,
94
+ # like direct subclasses of +BasicObject+.
95
+
96
+ ##
97
+ # :method: try!
98
+ #
99
+ # :call-seq:
100
+ # try!(*a, &b)
101
+ #
102
+ # Same as #try, but raises a +NoMethodError+ exception if the receiver is
103
+ # not +nil+ and does not implement the tried method.
104
+ #
105
+ # "a".try!(:upcase) # => "A"
106
+ # nil.try!(:upcase) # => nil
107
+ # 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Integer
108
+ end
109
+
110
+ class NilClass
111
+ # Calling +try+ on +nil+ always returns +nil+.
112
+ # It becomes especially helpful when navigating through associations that may return +nil+.
113
+ #
114
+ # nil.try(:name) # => nil
115
+ #
116
+ # Without +try+
117
+ # @person && @person.children.any? && @person.children.first.name
118
+ #
119
+ # With +try+
120
+ # @person.try(:children).try(:first).try(:name)
121
+ def try(_method_name = nil, *, **)
122
+ nil
123
+ end
124
+
125
+ # Calling +try!+ on +nil+ always returns +nil+.
126
+ #
127
+ # nil.try!(:name) # => nil
128
+ def try!(_method_name = nil, *, **)
129
+ nil
130
+ end
131
+ end
132
+
@@ -0,0 +1,108 @@
1
+ require "weakref"
2
+
3
+ module SigtermExtensions
4
+ # This module provides an internal implementation to track descendants
5
+ # which is faster than iterating through ObjectSpace.
6
+ module DescendantsTracker
7
+ @@direct_descendants = {}
8
+
9
+ class << self
10
+ def direct_descendants(klass)
11
+ descendants = @@direct_descendants[klass]
12
+ descendants ? descendants.to_a : []
13
+ end
14
+
15
+ def descendants(klass)
16
+ arr = []
17
+ accumulate_descendants(klass, arr)
18
+ arr
19
+ end
20
+
21
+ def clear
22
+ if defined? ActiveSupport::Dependencies
23
+ @@direct_descendants.each do |klass, descendants|
24
+ if Dependencies.autoloaded?(klass)
25
+ @@direct_descendants.delete(klass)
26
+ else
27
+ descendants.reject! { |v| Dependencies.autoloaded?(v) }
28
+ end
29
+ end
30
+ else
31
+ @@direct_descendants.clear
32
+ end
33
+ end
34
+
35
+ # This is the only method that is not thread safe, but is only ever called
36
+ # during the eager loading phase.
37
+ def store_inherited(klass, descendant)
38
+ (@@direct_descendants[klass] ||= DescendantsArray.new) << descendant
39
+ end
40
+
41
+ private
42
+ def accumulate_descendants(klass, acc)
43
+ if direct_descendants = @@direct_descendants[klass]
44
+ direct_descendants.each do |direct_descendant|
45
+ acc << direct_descendant
46
+ accumulate_descendants(direct_descendant, acc)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ def inherited(base)
53
+ DescendantsTracker.store_inherited(self, base)
54
+ super
55
+ end
56
+
57
+ def direct_descendants
58
+ DescendantsTracker.direct_descendants(self)
59
+ end
60
+
61
+ def descendants
62
+ DescendantsTracker.descendants(self)
63
+ end
64
+
65
+ # DescendantsArray is an array that contains weak references to classes.
66
+ class DescendantsArray # :nodoc:
67
+ include Enumerable
68
+
69
+ def initialize
70
+ @refs = []
71
+ end
72
+
73
+ def initialize_copy(orig)
74
+ @refs = @refs.dup
75
+ end
76
+
77
+ def <<(klass)
78
+ @refs << WeakRef.new(klass)
79
+ end
80
+
81
+ def each
82
+ @refs.reject! do |ref|
83
+ yield ref.__getobj__
84
+ false
85
+ rescue WeakRef::RefError
86
+ true
87
+ end
88
+ self
89
+ end
90
+
91
+ def refs_size
92
+ @refs.size
93
+ end
94
+
95
+ def cleanup!
96
+ @refs.delete_if { |ref| !ref.weakref_alive? }
97
+ end
98
+
99
+ def reject!
100
+ @refs.reject! do |ref|
101
+ yield ref.__getobj__
102
+ rescue WeakRef::RefError
103
+ true
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,47 @@
1
+ module SigtermExtensions
2
+ module GemMethods
3
+
4
+ # This can require a gem that's not in the Gemfile or gemspec
5
+ def unbundled_require(gem)
6
+ if defined?(::Bundler)
7
+ spec_path = Dir.glob("#{Gem.dir}/specifications/#{gem}-*.gemspec").last
8
+ if spec_path.nil?
9
+ warn "Couldn't find #{gem}"
10
+ return
11
+ end
12
+
13
+ spec = Gem::Specification.load spec_path
14
+ spec.activate
15
+ end
16
+
17
+ begin
18
+ require gem
19
+ yield if block_given?
20
+ rescue Exception => err
21
+ warn "Couldn't load #{gem}: #{err}"
22
+ end
23
+ end
24
+
25
+ def load_everything!
26
+ Gem::Specification.all.each do |gem|
27
+ gem.load_paths.each do |p|
28
+ $:.unshift(p) unless $LOAD_PATH.include?(p)
29
+ end
30
+ end
31
+ end
32
+
33
+ def add_gems_global_to_path
34
+ # This will load all global gems to load path
35
+ if defined?(::Bundler)
36
+ global_gemset = ENV['GEM_PATH'].split(':').grep(/ruby.*@global/).first
37
+ if global_gemset
38
+ all_global_gem_paths = Dir.glob("#{global_gemset}/gems/*")
39
+ all_global_gem_paths.each do |p|
40
+ gem_path = "#{p}/lib"
41
+ $LOAD_PATH << gem_path
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ module SigtermExtensions
2
+ class HashBinding
3
+ def initialize(hash)
4
+ @hash = hash.dup
5
+ end
6
+ def method_missing(m, *args, &block)
7
+ @hash[m.to_s]
8
+ end
9
+ def get_binding
10
+ binding
11
+ end
12
+ end
13
+ end
14
+ # while /<%=.*%>/.match(str) != nil
15
+ # str = ERB.new(str).result(binding)
16
+ # end
@@ -0,0 +1,339 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SigtermExtensions
4
+ # inflector
5
+ #
6
+ # @since 0.1.0
7
+ class Inflector
8
+ require_relative "inflector/version"
9
+ require_relative "inflector/inflections"
10
+
11
+ # Instantiate the inflector
12
+ #
13
+ # @param blk [Proc] an optional block to specify custom inflection rules
14
+ # @yieldparam [SigtermExtensions::Inflector::Inflections] the inflection rules
15
+ #
16
+ # @return [SigtermExtensions::Inflector] the inflector
17
+ #
18
+ # @since 0.1.0
19
+ #
20
+ # @example Basic usage
21
+ # require "sigterm_extensions/inflector"
22
+ #
23
+ # inflector = SigtermExtensions::Inflector.new
24
+ #
25
+ # @example Custom inflection rules
26
+ # require "sigterm_extensions/inflector"
27
+ #
28
+ # inflector = SigtermExtensions::Inflector.new do |inflections|
29
+ # inflections.plural "virus", "viruses" # specify a rule for #pluralize
30
+ # inflections.singular "thieves", "thief" # specify a rule for #singularize
31
+ # inflections.uncountable "inflector" # add an exception for an uncountable word
32
+ # end
33
+ def initialize(&blk)
34
+ @inflections = Inflections.build(&blk)
35
+ end
36
+
37
+ # Lower camelize a string
38
+ #
39
+ # @param input [String,Symbol] the input
40
+ # @return [String] the lower camelized string
41
+ #
42
+ # @since 0.1.3
43
+ #
44
+ # @example
45
+ # require "sigterm_extensions/inflector"
46
+ #
47
+ # inflector = SigtermExtensions::Inflector.new
48
+ # inflector.camelize_lower("data_mapper") # => "dataMapper"
49
+ def camelize_lower(input)
50
+ internal_camelize(input, false)
51
+ end
52
+
53
+ # Upper camelize a string
54
+ #
55
+ # @param input [String,Symbol] the input
56
+ # @return [String] the upper camelized string
57
+ #
58
+ # @since 0.1.3
59
+ #
60
+ # @example
61
+ # require "sigterm_extensions/inflector"
62
+ #
63
+ # inflector = SigtermExtensions::Inflector.new
64
+ # inflector.camelize_upper("data_mapper") # => "DataMapper"
65
+ # inflector.camelize_upper("sigterm_extensions/inflector") # => "SigtermExtensions::Inflector"
66
+ def camelize_upper(input)
67
+ internal_camelize(input, true)
68
+ end
69
+
70
+ alias :camelize :camelize_upper
71
+
72
+
73
+ # Find a constant with the name specified in the argument string
74
+ #
75
+ # The name is assumed to be the one of a top-level constant,
76
+ # constant scope of caller is ignored
77
+ #
78
+ # @param input [String,Symbol] the input
79
+ # @return [Class, Module] the class or module
80
+ #
81
+ # @since 0.1.0
82
+ #
83
+ # @example
84
+ # require "sigterm_extensions/inflector"
85
+ #
86
+ # inflector = SigtermExtensions::Inflector.new
87
+ # inflector.constantize("Module") # => Module
88
+ # inflector.constantize("SigtermExtensions::Inflector") # => SigtermExtensions::Inflector
89
+ def constantize(input)
90
+ Object.const_get(input)
91
+ end
92
+
93
+ # Classify a string
94
+ #
95
+ # @param input [String,Symbol] the input
96
+ # @return [String] the classified string
97
+ #
98
+ # @since 0.1.0
99
+ #
100
+ # @example
101
+ # require "sigterm_extensions/inflector"
102
+ #
103
+ # inflector = SigtermExtensions::Inflector.new
104
+ # inflector.classify("books") # => "Book"
105
+ def classify(input)
106
+ camelize(singularize(input.to_s.sub(/.*\./, "")))
107
+ end
108
+
109
+ # Dasherize a string
110
+ #
111
+ # @param input [String,Symbol] the input
112
+ # @return [String] the dasherized string
113
+ #
114
+ # @since 0.1.0
115
+ #
116
+ # @example
117
+ # require "sigterm_extensions/inflector"
118
+ #
119
+ # inflector = SigtermExtensions::Inflector.new
120
+ # inflector.dasherize("sigterm_extensions_inflector") # => "sigterm-extensions-inflector"
121
+ def dasherize(input)
122
+ input.to_s.tr("_", "-")
123
+ end
124
+
125
+ # Demodulize a string
126
+ #
127
+ # @param input [String,Symbol] the input
128
+ # @return [String] the demodulized string
129
+ #
130
+ # @since 0.1.0
131
+ #
132
+ # @example
133
+ # require "sigterm_extensions/inflector"
134
+ #
135
+ # inflector = SigtermExtensions::Inflector.new
136
+ # inflector.demodulize("SigtermExtensions::Inflector") # => "Inflector"
137
+ def demodulize(input)
138
+ input.to_s.split("::").last
139
+ end
140
+
141
+ # Humanize a string
142
+ #
143
+ # @param input [String,Symbol] the input
144
+ # @return [String] the humanized string
145
+ #
146
+ # @since 0.1.0
147
+ #
148
+ # @example
149
+ # require "sigterm_extensions/inflector"
150
+ #
151
+ # inflector = SigtermExtensions::Inflector.new
152
+ # inflector.humanize("dry_inflector") # => "SigtermExtensions inflector"
153
+ # inflector.humanize("author_id") # => "Author"
154
+ def humanize(input)
155
+ input = input.to_s
156
+ result = inflections.humans.apply_to(input)
157
+ result.chomp!("_id")
158
+ result.tr!("_", " ")
159
+ match = /(?<separator>\W)/.match(result)
160
+ separator = match ? match[:separator] : DEFAULT_SEPARATOR
161
+ result.split(separator).map.with_index { |word, index|
162
+ inflections.acronyms.apply_to(word, index.zero?)
163
+ }.join(separator)
164
+ end
165
+
166
+ # Creates a foreign key name
167
+ #
168
+ # @param input [String, Symbol] the input
169
+ # @return [String] foreign key
170
+ #
171
+ # @example
172
+ # require "sigterm_extensions/inflector"
173
+ #
174
+ # inflector = SigtermExtensions::Inflector.new
175
+ # inflector.foreign_key("Message") => "message_id"
176
+ def foreign_key(input)
177
+ "#{underscore(demodulize(input))}_id"
178
+ end
179
+
180
+ # Ordinalize a number
181
+ #
182
+ # @param number [Integer] the input
183
+ # @return [String] the ordinalized number
184
+ #
185
+ # @since 0.1.0
186
+ #
187
+ # @example
188
+ # require "sigterm_extensions/inflector"
189
+ #
190
+ # inflector = SigtermExtensions::Inflector.new
191
+ # inflector.ordinalize(1) # => "1st"
192
+ # inflector.ordinalize(2) # => "2nd"
193
+ # inflector.ordinalize(3) # => "3rd"
194
+ # inflector.ordinalize(10) # => "10th"
195
+ # inflector.ordinalize(23) # => "23rd"
196
+ def ordinalize(number) # rubocop:disable Metrics/MethodLength
197
+ abs_value = number.abs
198
+
199
+ if ORDINALIZE_TH.key?(abs_value % 100)
200
+ "#{number}th"
201
+ else
202
+ case abs_value % 10
203
+ when 1 then "#{number}st"
204
+ when 2 then "#{number}nd"
205
+ when 3 then "#{number}rd"
206
+ else "#{number}th"
207
+ end
208
+ end
209
+ end
210
+
211
+ # Pluralize a string
212
+ #
213
+ # @param input [String,Symbol] the input
214
+ # @return [String] the pluralized string
215
+ #
216
+ # @since 0.1.0
217
+ #
218
+ # @example
219
+ # require "sigterm_extensions/inflector"
220
+ #
221
+ # inflector = SigtermExtensions::Inflector.new
222
+ # inflector.pluralize("book") # => "books"
223
+ # inflector.pluralize("money") # => "money"
224
+ def pluralize(input)
225
+ input = input.to_s
226
+ return input if uncountable?(input)
227
+ inflections.plurals.apply_to(input)
228
+ end
229
+
230
+ # Singularize a string
231
+ #
232
+ # @param input [String] the input
233
+ # @return [String] the singularized string
234
+ #
235
+ # @since 0.1.0
236
+ #
237
+ # @example
238
+ # require "sigterm_extensions/inflector"
239
+ #
240
+ # inflector = SigtermExtensions::Inflector.new
241
+ # inflector.singularize("books") # => "book"
242
+ # inflector.singularize("money") # => "money"
243
+ def singularize(input)
244
+ input = input.to_s
245
+ return input if uncountable?(input)
246
+ inflections.singulars.apply_to(input)
247
+ end
248
+
249
+ # Tableize a string
250
+ #
251
+ # @param input [String,Symbol] the input
252
+ # @return [String] the tableized string
253
+ #
254
+ # @since 0.1.0
255
+ #
256
+ # @example
257
+ # require "sigterm_extensions/inflector"
258
+ #
259
+ # inflector = SigtermExtensions::Inflector.new
260
+ # inflector.tableize("Book") # => "books"
261
+ def tableize(input)
262
+ input = input.to_s.gsub(/::/, "_")
263
+ pluralize(underscore(input))
264
+ end
265
+
266
+ # Underscore a string
267
+ #
268
+ # @param input [String,Symbol] the input
269
+ # @return [String] the underscored string
270
+ #
271
+ # @since 0.1.0
272
+ #
273
+ # @example
274
+ # require "sigterm_extensions/inflector"
275
+ #
276
+ # inflector = SigtermExtensions::Inflector.new
277
+ # inflector.underscore("sigterm-extensions-inflector") # => "sigterm_extensions_inflector"
278
+ def underscore(input)
279
+ input = input.to_s.gsub("::", "/")
280
+ input.gsub!(inflections.acronyms.regex) do
281
+ m1 = Regexp.last_match(1)
282
+ m2 = Regexp.last_match(2)
283
+ "#{m1 ? '_' : '' }#{m2.downcase}"
284
+ end
285
+ input.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
286
+ input.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
287
+ input.tr!("-", "_")
288
+ input.downcase!
289
+ input
290
+ end
291
+
292
+ # Check if the input is an uncountable word
293
+ #
294
+ # @param input [String] the input
295
+ # @return [TrueClass,FalseClass] the result of the check
296
+ #
297
+ # @since 0.1.0
298
+ # @api private
299
+ def uncountable?(input)
300
+ !(input =~ /\A[[:space:]]*\z/).nil? || inflections.uncountables.include?(input.downcase)
301
+ end
302
+
303
+ # @return [String]
304
+ #
305
+ # @since 0.2.0
306
+ # @api public
307
+ def to_s
308
+ '#<SigtermExtensions::Inflector>'
309
+ end
310
+ alias inspect to_s
311
+
312
+ private
313
+
314
+ # @since 0.1.0
315
+ # @api private
316
+ ORDINALIZE_TH = (11..13).each_with_object({}) { |n, ret| ret[n] = true }.freeze
317
+
318
+ # @since 0.1.2
319
+ # @api private
320
+ DEFAULT_SEPARATOR = " "
321
+
322
+ attr_reader :inflections
323
+
324
+ # @since 0.1.3
325
+ # @api private
326
+ def internal_camelize(input, upper)
327
+ input = input.to_s.dup
328
+ input.sub!(/^[a-z\d]*/) { |match| inflections.acronyms.apply_to(match, upper) }
329
+ input.gsub!(%r{(?:_|(/))([a-z\d]*)}i) do
330
+ m1 = Regexp.last_match(1)
331
+ m2 = Regexp.last_match(2)
332
+ "#{m1}#{inflections.acronyms.apply_to(m2)}"
333
+ end
334
+ input.gsub!("/", "::")
335
+ input
336
+ end
337
+
338
+ end
339
+ end