bridgetown-foundation 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +7 -0
- data/Rakefile +11 -0
- data/benchmark/refinements.rb +50 -0
- data/bridgetown-foundation.gemspec +29 -0
- data/lib/bridgetown/foundation/core_ext/class.rb +24 -0
- data/lib/bridgetown/foundation/core_ext/string.rb +38 -0
- data/lib/bridgetown/foundation/packages/ansi.rb +54 -0
- data/lib/bridgetown/foundation/packages/pid_tracker.rb +37 -0
- data/lib/bridgetown/foundation/packages/safe_translations.rb +51 -0
- data/lib/bridgetown/foundation/questionable_string.rb +19 -0
- data/lib/bridgetown/foundation/refine_ext/deep_duplicatable.rb +44 -0
- data/lib/bridgetown/foundation/refine_ext/module.rb +40 -0
- data/lib/bridgetown/foundation/refine_ext/object.rb +68 -0
- data/lib/bridgetown/foundation/refine_ext/string.rb +37 -0
- data/lib/bridgetown/foundation/version.rb +8 -0
- data/lib/bridgetown-foundation.rb +70 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 00a2692340742728b14ce61beb79b3181409376be73f56c21a60db4e3d28c3ee
|
4
|
+
data.tar.gz: fc2ae32d07c3f218d98ed6409abab7431e6927078005c6dc4dbd158d054ce4c5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 82722f2c1d63bbc05f2d8de93290999316162c0de9f55d91c24fbe831ee67a7b0335c1e3c91846038518b7d944e413c6b1be795fcead56e53815b068c2c2de72
|
7
|
+
data.tar.gz: de9adb2dc49ed52b36fe7f61e7f10f29e30b8b12fced50cd8e2cc678b563f11001c79d038fead8a786898963c8be45352b85207a14aa65be21423abeecc756f6
|
data/.rubocop.yml
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "benchmark"
|
4
|
+
|
5
|
+
class TestInclusion
|
6
|
+
module StringAdder
|
7
|
+
def included_add(num)
|
8
|
+
to_i + num
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
String.include StringAdder
|
13
|
+
|
14
|
+
def self.perform
|
15
|
+
raise "crash!" unless "10".included_add(20) == 30
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module StringAdderRefinement
|
20
|
+
refine String do
|
21
|
+
def refined_add(num)
|
22
|
+
to_i + num
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class TestRefinement
|
28
|
+
using StringAdderRefinement
|
29
|
+
|
30
|
+
def self.perform
|
31
|
+
raise "crash!" unless "10".refined_add(20) == 30
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
raise "Unconfirmed!" unless "".respond_to?(:included_add)
|
36
|
+
raise "Unconfirmed!" if "".respond_to?(:refined_add)
|
37
|
+
|
38
|
+
n = 1_000_000
|
39
|
+
Benchmark.bmbm(12) do |x|
|
40
|
+
x.report("inclusion:") do
|
41
|
+
n.times do
|
42
|
+
TestInclusion.perform
|
43
|
+
end
|
44
|
+
end
|
45
|
+
x.report("refinements:") do
|
46
|
+
n.times do
|
47
|
+
TestRefinement.perform
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/bridgetown/foundation/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "bridgetown-foundation"
|
7
|
+
spec.version = Bridgetown::Foundation::VERSION
|
8
|
+
spec.author = "Bridgetown Team"
|
9
|
+
spec.email = "maintainers@bridgetownrb.com"
|
10
|
+
spec.summary = "Ruby language extensions and other utilities useful for the Bridgetown ecosystem"
|
11
|
+
spec.homepage = "https://github.com/bridgetownrb/bridgetown/tree/main/bridgetown-foundation"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = ">= 3.1"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r!^(test|script)/!) }
|
16
|
+
spec.require_paths = ["lib"]
|
17
|
+
|
18
|
+
spec.metadata = {
|
19
|
+
"source_code_uri" => "https://github.com/bridgetownrb/bridgetown",
|
20
|
+
"bug_tracker_uri" => "https://github.com/bridgetownrb/bridgetown/issues",
|
21
|
+
"changelog_uri" => "https://github.com/bridgetownrb/bridgetown/releases",
|
22
|
+
"homepage_uri" => spec.homepage,
|
23
|
+
"rubygems_mfa_required" => "true",
|
24
|
+
}
|
25
|
+
|
26
|
+
spec.add_dependency("hash_with_dot_access", "~> 2.0")
|
27
|
+
spec.add_dependency("inclusive", "~> 1.0")
|
28
|
+
spec.add_dependency("zeitwerk", "~> 2.5")
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module CoreExt
|
5
|
+
module Class
|
6
|
+
module Descendants
|
7
|
+
def descendants
|
8
|
+
direct_children = subclasses.select do |klass|
|
9
|
+
next true if klass.name.nil? # anonymous class
|
10
|
+
|
11
|
+
# We do this to weed out old classes pre-Zeitwerk reload
|
12
|
+
klass == Kernel.const_get(klass.name)
|
13
|
+
rescue NameError
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
(direct_children + direct_children.map(&:descendants)).flatten
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
::Class.include Descendants
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module CoreExt
|
5
|
+
module String
|
6
|
+
module Colorize
|
7
|
+
class << self
|
8
|
+
extend Inclusive::Class
|
9
|
+
|
10
|
+
# @return [Bridgetown::Foundation::Packages::Ansi]
|
11
|
+
public_packages def ansi = [Bridgetown::Foundation::Packages::Ansi]
|
12
|
+
|
13
|
+
def included(klass)
|
14
|
+
ansi.tap do |a|
|
15
|
+
a.colors.each_key do |color|
|
16
|
+
klass.define_method(color) { |*args| a.public_send(color, self, *args) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Reset output colors back to a regular string output
|
23
|
+
def reset_ansi
|
24
|
+
Colorize.ansi.reset(self)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module StartsWithAndEndsWith
|
29
|
+
def self.included(klass)
|
30
|
+
klass.alias_method :starts_with?, :start_with?
|
31
|
+
klass.alias_method :ends_with?, :end_with?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
::String.include Colorize, StartsWithAndEndsWith
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module Packages
|
5
|
+
module Ansi
|
6
|
+
extend self
|
7
|
+
|
8
|
+
ESCAPE = format("%c", 27)
|
9
|
+
MATCH = %r!#{ESCAPE}\[(?:\d+)(?:;\d+)*(j|k|m|s|u|A|B|G)|\e\(B\e\[m!ix
|
10
|
+
COLORS = {
|
11
|
+
bold: 1,
|
12
|
+
black: 30,
|
13
|
+
red: 31,
|
14
|
+
green: 32,
|
15
|
+
yellow: 33,
|
16
|
+
blue: 34,
|
17
|
+
magenta: 35,
|
18
|
+
cyan: 36,
|
19
|
+
white: 37,
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
def colors = COLORS
|
23
|
+
|
24
|
+
# Strip ANSI from the current string. It also strips cursor stuff,
|
25
|
+
# well some of it, and it also strips some other stuff that a lot of
|
26
|
+
# the other ANSI strippers don't.
|
27
|
+
def strip(str)
|
28
|
+
str.gsub MATCH, ""
|
29
|
+
end
|
30
|
+
|
31
|
+
# Does the string include ANSI color codes?
|
32
|
+
def has?(str)
|
33
|
+
!!(str =~ MATCH)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Reset the color back to the default color so that you do not leak any
|
37
|
+
# colors when you move onto the next line. This is probably normally
|
38
|
+
# used as part of a wrapper so that we don't leak colors.
|
39
|
+
def reset(str = "")
|
40
|
+
@ansi_reset ||= format("%c[0m", 27)
|
41
|
+
"#{@ansi_reset}#{str}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# SEE: `self::COLORS` for a list of methods. They are mostly
|
45
|
+
# standard base colors supported by pretty much any xterm-color, we do
|
46
|
+
# not need more than the base colors so we do not include them.
|
47
|
+
COLORS.each do |color, num|
|
48
|
+
define_method color do |str|
|
49
|
+
"#{format("%c", 27)}[#{num}m#{str}#{reset}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module Packages
|
5
|
+
module PidTracker
|
6
|
+
def create_pid_dir
|
7
|
+
FileUtils.mkdir_p pids_dir
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_pid(pid, file:)
|
11
|
+
File.write pidfile_for(file), "#{pid}\n", mode: "a+"
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_pidfile(file)
|
15
|
+
File.readlines pidfile_for(file), chomp: true
|
16
|
+
end
|
17
|
+
|
18
|
+
def remove_pidfile(file)
|
19
|
+
File.delete pidfile_for(file)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def root_dir
|
25
|
+
Dir.pwd
|
26
|
+
end
|
27
|
+
|
28
|
+
def pids_dir
|
29
|
+
File.join(root_dir, "tmp", "pids")
|
30
|
+
end
|
31
|
+
|
32
|
+
def pidfile_for(file)
|
33
|
+
File.join(pids_dir, "#{file}.pid")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module Packages
|
5
|
+
# NOTE: this is tested by `test/test_ruby_helpers.rb` in bridgetown-core
|
6
|
+
#
|
7
|
+
# This is loosely based on the HtmlSafeTranslation module from ActiveSupport, but you can
|
8
|
+
# actually use it for any kind of safety use case in a translation setting because its
|
9
|
+
# decoupled from any specific escaping or safety mechanisms.
|
10
|
+
module SafeTranslations
|
11
|
+
extend Inclusive::Public
|
12
|
+
|
13
|
+
def translate(key, escaper, safety_method = :html_safe, **options)
|
14
|
+
safe_options = escape_translation_options(options, escaper)
|
15
|
+
|
16
|
+
i18n_error = false
|
17
|
+
|
18
|
+
exception_handler = ->(*args) do
|
19
|
+
i18n_error = true
|
20
|
+
I18n.exception_handler.(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
I18n.translate(key, **safe_options, exception_handler:).then do |translation|
|
24
|
+
i18n_error ? translation : safe_translation(translation, safety_method)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
public_function :translate
|
29
|
+
|
30
|
+
def escape_translation_options(options, escaper)
|
31
|
+
@reserved_i18n_keys ||= I18n::RESERVED_KEYS.to_set
|
32
|
+
|
33
|
+
options.to_h do |name, value|
|
34
|
+
unless @reserved_i18n_keys.include?(name) || (name == :count && value.is_a?(Numeric))
|
35
|
+
next [name, escaper.(value)]
|
36
|
+
end
|
37
|
+
|
38
|
+
[name, value]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def safe_translation(translation, safety_method)
|
43
|
+
@safe_value ||= -> { _1.respond_to?(safety_method) ? _1.send(safety_method) : _1 }
|
44
|
+
|
45
|
+
return translation.map { @safe_value.(_1) } if translation.respond_to?(:map)
|
46
|
+
|
47
|
+
@safe_value.(translation)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
class QuestionableString < ::String
|
5
|
+
def method_missing(method_name, *args)
|
6
|
+
value = method_name.to_s
|
7
|
+
if value.end_with?("?")
|
8
|
+
value.chop!
|
9
|
+
return self == value
|
10
|
+
end
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def respond_to_missing?(method_name, include_private = false)
|
16
|
+
method_name.end_with?("?") || super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module RefineExt
|
5
|
+
# This is a very simplistic algorithm…it essentially just works on the Array/Hash values level,
|
6
|
+
# which for our purposes is fine.
|
7
|
+
module DeepDuplicatable
|
8
|
+
refine ::Hash do
|
9
|
+
def deep_dup
|
10
|
+
hash = dup
|
11
|
+
each do |key, value|
|
12
|
+
hash.delete(key)
|
13
|
+
if key.is_a?(::String) || key.is_a?(::Symbol)
|
14
|
+
hash[key] = value.dup
|
15
|
+
else
|
16
|
+
hash[key.dup] = if value.is_a?(Array) || value.is_a?(Hash)
|
17
|
+
value.deep_dup
|
18
|
+
else
|
19
|
+
value.dup
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
hash
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
refine ::Array do
|
28
|
+
def deep_dep
|
29
|
+
map do |item|
|
30
|
+
next item.dup unless item.is_a?(Array) || item.is_a?(Hash)
|
31
|
+
|
32
|
+
item.deep_dup
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module Bridgetown
|
41
|
+
module Refinements
|
42
|
+
include Foundation::RefineExt::DeepDuplicatable
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module RefineExt
|
5
|
+
module Module
|
6
|
+
using RefineExt::Object
|
7
|
+
|
8
|
+
refine ::Module do
|
9
|
+
def nested_within?(other)
|
10
|
+
return false if self == other
|
11
|
+
|
12
|
+
other.nested_parents.within?(nested_parents) #[1..])
|
13
|
+
end
|
14
|
+
|
15
|
+
def nested_parents
|
16
|
+
return [] unless name
|
17
|
+
|
18
|
+
nesting_segments = name.split("::")[...-1]
|
19
|
+
nesting_segments.map.each_with_index do |_nesting_name, index|
|
20
|
+
Kernel.const_get(nesting_segments[..-(index + 1)].join("::"))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def nested_parent
|
25
|
+
nested_parents.first
|
26
|
+
end
|
27
|
+
|
28
|
+
def nested_name
|
29
|
+
name&.split("::")&.last
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Bridgetown
|
37
|
+
module Refinements
|
38
|
+
include Foundation::RefineExt::Module
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module RefineExt
|
5
|
+
module Object
|
6
|
+
refine ::Object do
|
7
|
+
# This method lets you check if the receiver is "within" the other object. In most cases,
|
8
|
+
# this check is accomplished via the `include?` method…aka, `10.within? [5, 10]` would
|
9
|
+
# return `true` as `[5, 10].include? 10` is true. And String/String comparison are
|
10
|
+
# case-insensivitve.
|
11
|
+
#
|
12
|
+
# However, for certain comparison types: Module/Class, Hash, and Set, the lesser-than (`<`)
|
13
|
+
# operator is used instead. This is so you can check `BigDecimal.within? Numeric`,
|
14
|
+
# `{easy_as: 123}.within?({indeed: "it's true", easy_as: 123})`, and if a Set is a
|
15
|
+
# `proper_subset?` of another Set.
|
16
|
+
#
|
17
|
+
# For Array/Array comparisons, a difference is checked, so `[1,2].within? [3,2,1]` is true,
|
18
|
+
# but `[1,2].within? [2,3]` is false.
|
19
|
+
#
|
20
|
+
# Also for Range, the `cover?` method is used instead of `include?`.
|
21
|
+
#
|
22
|
+
# @param other [Object] for determining if receiver lies within this value
|
23
|
+
# @return [Boolean]
|
24
|
+
def within?(other) # rubocop:disable Metrics
|
25
|
+
# rubocop:disable Style/IfUnlessModifier
|
26
|
+
if is_a?(Module) && other.is_a?(Module)
|
27
|
+
return self < other
|
28
|
+
end
|
29
|
+
|
30
|
+
if (is_a?(Hash) && other.is_a?(Hash)) || (is_a?(Set) && other.is_a?(Set))
|
31
|
+
return self < other
|
32
|
+
end
|
33
|
+
|
34
|
+
if is_a?(Array) && other.is_a?(Array)
|
35
|
+
return false if empty?
|
36
|
+
|
37
|
+
return difference(other).empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
if other.is_a?(Range)
|
41
|
+
return other.cover?(self) == true
|
42
|
+
end
|
43
|
+
|
44
|
+
if is_a?(::String) && other.is_a?(::String)
|
45
|
+
return other.downcase.include?(downcase)
|
46
|
+
end
|
47
|
+
|
48
|
+
other&.include?(self) == true
|
49
|
+
# rubocop:enable Style/IfUnlessModifier
|
50
|
+
rescue NoMethodError
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
# NOTE: if you _really_ need to preserve Active Support's `in?` functionality, you can just
|
55
|
+
# require "active_support/core_ext/object/inclusion"
|
56
|
+
def in?(...) = Bridgetown::Foundation.deprecation_warning(
|
57
|
+
self, :in?, :within?, 2024, 12
|
58
|
+
).then { within?(...) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module Bridgetown
|
65
|
+
module Refinements
|
66
|
+
include Foundation::RefineExt::Object
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown::Foundation
|
4
|
+
module RefineExt
|
5
|
+
module String
|
6
|
+
refine ::String do
|
7
|
+
def indent!(indent_by, *args)
|
8
|
+
if args.length.positive?
|
9
|
+
Kernel.warn "multiple arguments aren't supported by `indent!' in Bridgetown", uplevel: 1
|
10
|
+
end
|
11
|
+
|
12
|
+
gsub! %r!^(?\!$)!, " " * indent_by
|
13
|
+
end
|
14
|
+
|
15
|
+
def indent(indent_by, *args)
|
16
|
+
if args.length.positive?
|
17
|
+
Kernel.warn "multiple arguments aren't supported by `indent' in Bridgetown", uplevel: 1
|
18
|
+
end
|
19
|
+
|
20
|
+
dup.indent!(indent_by)
|
21
|
+
end
|
22
|
+
|
23
|
+
def questionable = Bridgetown::Foundation::QuestionableString.new(self)
|
24
|
+
|
25
|
+
def inquiry = Bridgetown::Foundation.deprecation_warning(
|
26
|
+
self, :inquiry, :questionable, 2024, 12
|
27
|
+
).then { questionable }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module Bridgetown
|
34
|
+
module Refinements
|
35
|
+
include Foundation::RefineExt::String
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bridgetown/foundation/version"
|
4
|
+
require "hash_with_dot_access"
|
5
|
+
require "inclusive"
|
6
|
+
require "zeitwerk"
|
7
|
+
require "delegate"
|
8
|
+
|
9
|
+
module Bridgetown::Foundation
|
10
|
+
# This is loosly based on the `deprecate` method in `Gem::Deprecate`
|
11
|
+
#
|
12
|
+
# @param target [Object]
|
13
|
+
# @param name [Symbol] e.g. `:howdy`
|
14
|
+
# @param repl [Symbol] e.g. `:hello`
|
15
|
+
# @param year [Integer] e.g. `2025`
|
16
|
+
# @param month [Integer] e.g. `1` for January
|
17
|
+
def self.deprecation_warning(target, name, repl, year, month) # rubocop:disable Metrics/ParameterLists
|
18
|
+
klass = target.is_a?(Module)
|
19
|
+
target = klass ? "#{self}." : "#{self.class}#"
|
20
|
+
msg = [
|
21
|
+
"NOTE: #{target}#{name} is deprecated",
|
22
|
+
repl == :none ? " with no replacement" : "; use #{repl} instead",
|
23
|
+
format(". It will be removed on or after %4d-%02d.", year, month), # rubocop:disable Style/FormatStringToken
|
24
|
+
"\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
|
25
|
+
]
|
26
|
+
warn "#{msg.join}."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# You can add `using Bridgetown::Refinements` to any portion of your Ruby code to load in all
|
31
|
+
# of the refinements available in Foundation. Or you can add a using statement for a particular
|
32
|
+
# refinement which lives inside `Bridgetown::Foundation::RefineExt`.
|
33
|
+
module Bridgetown::Refinements
|
34
|
+
include HashWithDotAccess::Refinements
|
35
|
+
end
|
36
|
+
|
37
|
+
Zeitwerk.with_loader do |l|
|
38
|
+
l.push_dir "#{__dir__}/bridgetown/foundation", namespace: Bridgetown::Foundation
|
39
|
+
l.ignore "#{__dir__}/bridgetown/foundation/version.rb"
|
40
|
+
l.setup
|
41
|
+
l.eager_load
|
42
|
+
end
|
43
|
+
|
44
|
+
module Bridgetown
|
45
|
+
# Any method call sent will be passed along to the wrapped object with refinements activated
|
46
|
+
class WrappedObjectWithRefinements < SimpleDelegator
|
47
|
+
using Bridgetown::Refinements
|
48
|
+
|
49
|
+
# rubocop:disable Style/MissingRespondToMissing
|
50
|
+
def method_missing(method, ...) = __getobj__.send(method, ...)
|
51
|
+
# rubocop:enable Style/MissingRespondToMissing
|
52
|
+
end
|
53
|
+
|
54
|
+
# Call this method to wrap any object(s) in order to use Foundation's refinements
|
55
|
+
#
|
56
|
+
# @param *obj [Object]
|
57
|
+
# @return [WrappedObjectWithRefinements]
|
58
|
+
def self.refine(*obj)
|
59
|
+
if obj.length == 1
|
60
|
+
WrappedObjectWithRefinements.new(obj[0])
|
61
|
+
else
|
62
|
+
obj.map { WrappedObjectWithRefinements.new _1 }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.add_refinement(mod, &)
|
67
|
+
Bridgetown::Refinements.include(mod)
|
68
|
+
Bridgetown::WrappedObjectWithRefinements.class_eval(&)
|
69
|
+
end
|
70
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bridgetown-foundation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0.beta1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bridgetown Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-08-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hash_with_dot_access
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: inclusive
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: zeitwerk
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.5'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.5'
|
55
|
+
description:
|
56
|
+
email: maintainers@bridgetownrb.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- ".rubocop.yml"
|
62
|
+
- Rakefile
|
63
|
+
- benchmark/refinements.rb
|
64
|
+
- bridgetown-foundation.gemspec
|
65
|
+
- lib/bridgetown-foundation.rb
|
66
|
+
- lib/bridgetown/foundation/core_ext/class.rb
|
67
|
+
- lib/bridgetown/foundation/core_ext/string.rb
|
68
|
+
- lib/bridgetown/foundation/packages/ansi.rb
|
69
|
+
- lib/bridgetown/foundation/packages/pid_tracker.rb
|
70
|
+
- lib/bridgetown/foundation/packages/safe_translations.rb
|
71
|
+
- lib/bridgetown/foundation/questionable_string.rb
|
72
|
+
- lib/bridgetown/foundation/refine_ext/deep_duplicatable.rb
|
73
|
+
- lib/bridgetown/foundation/refine_ext/module.rb
|
74
|
+
- lib/bridgetown/foundation/refine_ext/object.rb
|
75
|
+
- lib/bridgetown/foundation/refine_ext/string.rb
|
76
|
+
- lib/bridgetown/foundation/version.rb
|
77
|
+
homepage: https://github.com/bridgetownrb/bridgetown/tree/main/bridgetown-foundation
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata:
|
81
|
+
source_code_uri: https://github.com/bridgetownrb/bridgetown
|
82
|
+
bug_tracker_uri: https://github.com/bridgetownrb/bridgetown/issues
|
83
|
+
changelog_uri: https://github.com/bridgetownrb/bridgetown/releases
|
84
|
+
homepage_uri: https://github.com/bridgetownrb/bridgetown/tree/main/bridgetown-foundation
|
85
|
+
rubygems_mfa_required: 'true'
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '3.1'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 1.3.1
|
100
|
+
requirements: []
|
101
|
+
rubygems_version: 3.3.26
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: Ruby language extensions and other utilities useful for the Bridgetown ecosystem
|
105
|
+
test_files: []
|