sigterm_extensions 0.0.4
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +6 -0
- data/LICENSE.md +0 -0
- data/README.md +0 -0
- data/bin/ctxirb +156 -0
- data/lib/git.rb +166 -0
- data/lib/git/LICENSE +21 -0
- data/lib/git/author.rb +14 -0
- data/lib/git/base.rb +551 -0
- data/lib/git/base/factory.rb +75 -0
- data/lib/git/branch.rb +126 -0
- data/lib/git/branches.rb +71 -0
- data/lib/git/config.rb +22 -0
- data/lib/git/diff.rb +159 -0
- data/lib/git/index.rb +5 -0
- data/lib/git/lib.rb +1041 -0
- data/lib/git/log.rb +128 -0
- data/lib/git/object.rb +312 -0
- data/lib/git/path.rb +31 -0
- data/lib/git/remote.rb +36 -0
- data/lib/git/repository.rb +6 -0
- data/lib/git/stash.rb +27 -0
- data/lib/git/stashes.rb +55 -0
- data/lib/git/status.rb +199 -0
- data/lib/git/version.rb +5 -0
- data/lib/git/working_directory.rb +4 -0
- data/lib/sigterm_extensions.rb +75 -0
- data/lib/sigterm_extensions/all.rb +12 -0
- data/lib/sigterm_extensions/backtrace_cleaner.rb +129 -0
- data/lib/sigterm_extensions/callbacks.rb +847 -0
- data/lib/sigterm_extensions/concern.rb +169 -0
- data/lib/sigterm_extensions/configurable.rb +38 -0
- data/lib/sigterm_extensions/core_ext.rb +4 -0
- data/lib/sigterm_extensions/core_ext/array.rb +3 -0
- data/lib/sigterm_extensions/core_ext/array/extract.rb +19 -0
- data/lib/sigterm_extensions/core_ext/array/extract_options.rb +29 -0
- data/lib/sigterm_extensions/core_ext/class.rb +3 -0
- data/lib/sigterm_extensions/core_ext/class/attribute.rb +139 -0
- data/lib/sigterm_extensions/core_ext/class/attribute_accessors.rb +4 -0
- data/lib/sigterm_extensions/core_ext/class/subclasses.rb +52 -0
- data/lib/sigterm_extensions/core_ext/custom.rb +12 -0
- data/lib/sigterm_extensions/core_ext/digest.rb +3 -0
- data/lib/sigterm_extensions/core_ext/digest/uuid.rb +51 -0
- data/lib/sigterm_extensions/core_ext/enumerable.rb +232 -0
- data/lib/sigterm_extensions/core_ext/file.rb +3 -0
- data/lib/sigterm_extensions/core_ext/file/atomic.rb +68 -0
- data/lib/sigterm_extensions/core_ext/hash.rb +3 -0
- data/lib/sigterm_extensions/core_ext/hash/deep_merge.rb +41 -0
- data/lib/sigterm_extensions/core_ext/hash/deep_transform_values.rb +44 -0
- data/lib/sigterm_extensions/core_ext/hash/except.rb +22 -0
- data/lib/sigterm_extensions/core_ext/hash/keys.rb +141 -0
- data/lib/sigterm_extensions/core_ext/hash/reverse_merge.rb +23 -0
- data/lib/sigterm_extensions/core_ext/hash/slice.rb +24 -0
- data/lib/sigterm_extensions/core_ext/kernel.rb +3 -0
- data/lib/sigterm_extensions/core_ext/kernel/concern.rb +12 -0
- data/lib/sigterm_extensions/core_ext/kernel/reporting.rb +43 -0
- data/lib/sigterm_extensions/core_ext/kernel/singleton_class.rb +6 -0
- data/lib/sigterm_extensions/core_ext/load_error.rb +7 -0
- data/lib/sigterm_extensions/core_ext/module.rb +3 -0
- data/lib/sigterm_extensions/core_ext/module/aliasing.rb +29 -0
- data/lib/sigterm_extensions/core_ext/module/anonymous.rb +28 -0
- data/lib/sigterm_extensions/core_ext/module/attr_internal.rb +36 -0
- data/lib/sigterm_extensions/core_ext/module/attribute_accessors.rb +208 -0
- data/lib/sigterm_extensions/core_ext/module/attribute_accessors_per_thread.rb +146 -0
- data/lib/sigterm_extensions/core_ext/module/concerning.rb +132 -0
- data/lib/sigterm_extensions/core_ext/module/delegation.rb +319 -0
- data/lib/sigterm_extensions/core_ext/module/redefine_method.rb +38 -0
- data/lib/sigterm_extensions/core_ext/module/remove_method.rb +15 -0
- data/lib/sigterm_extensions/core_ext/name_error.rb +36 -0
- data/lib/sigterm_extensions/core_ext/object.rb +3 -0
- data/lib/sigterm_extensions/core_ext/object/blank.rb +153 -0
- data/lib/sigterm_extensions/core_ext/object/colors.rb +39 -0
- data/lib/sigterm_extensions/core_ext/object/duplicable.rb +47 -0
- data/lib/sigterm_extensions/core_ext/object/inclusion.rb +27 -0
- data/lib/sigterm_extensions/core_ext/object/instance_variables.rb +28 -0
- data/lib/sigterm_extensions/core_ext/object/methods.rb +61 -0
- data/lib/sigterm_extensions/core_ext/object/with_options.rb +80 -0
- data/lib/sigterm_extensions/core_ext/range.rb +3 -0
- data/lib/sigterm_extensions/core_ext/range/compare_range.rb +74 -0
- data/lib/sigterm_extensions/core_ext/range/conversions.rb +39 -0
- data/lib/sigterm_extensions/core_ext/range/overlaps.rb +8 -0
- data/lib/sigterm_extensions/core_ext/securerandom.rb +43 -0
- data/lib/sigterm_extensions/core_ext/string.rb +3 -0
- data/lib/sigterm_extensions/core_ext/string/access.rb +93 -0
- data/lib/sigterm_extensions/core_ext/string/filters.rb +143 -0
- data/lib/sigterm_extensions/core_ext/string/starts_ends_with.rb +4 -0
- data/lib/sigterm_extensions/core_ext/string/strip.rb +25 -0
- data/lib/sigterm_extensions/core_ext/tryable.rb +132 -0
- data/lib/sigterm_extensions/descendants_tracker.rb +108 -0
- data/lib/sigterm_extensions/gem_methods.rb +47 -0
- data/lib/sigterm_extensions/hash_binding.rb +16 -0
- data/lib/sigterm_extensions/inflector.rb +339 -0
- data/lib/sigterm_extensions/inflector/acronyms.rb +42 -0
- data/lib/sigterm_extensions/inflector/inflections.rb +249 -0
- data/lib/sigterm_extensions/inflector/inflections/defaults.rb +117 -0
- data/lib/sigterm_extensions/inflector/rules.rb +37 -0
- data/lib/sigterm_extensions/inflector/version.rb +8 -0
- data/lib/sigterm_extensions/interactive_editor.rb +120 -0
- data/lib/sigterm_extensions/lazy.rb +34 -0
- data/lib/sigterm_extensions/lazy_load_hooks.rb +79 -0
- data/lib/sigterm_extensions/option_merger.rb +32 -0
- data/lib/sigterm_extensions/ordered_hash.rb +48 -0
- data/lib/sigterm_extensions/ordered_options.rb +83 -0
- data/lib/sigterm_extensions/paths.rb +235 -0
- data/lib/sigterm_extensions/per_thread_registry.rb +58 -0
- data/lib/sigterm_extensions/proxy_object.rb +14 -0
- data/lib/sigterm_extensions/staging/boot.rb +31 -0
- data/lib/sigterm_extensions/staging/boot/bundler_patch.rb +24 -0
- data/lib/sigterm_extensions/staging/boot/command.rb +26 -0
- data/lib/sigterm_extensions/staging/boot/gemfile_next_auto_sync.rb +79 -0
- data/lib/sigterm_extensions/version.rb +4 -0
- data/lib/sigterm_extensions/wrappable.rb +16 -0
- data/sigterm_extensions.gemspec +42 -0
- data/templates/dotpryrc.rb.erb +124 -0
- metadata +315 -0
|
@@ -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
|