tins 1.43.0 → 1.44.0
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 +4 -4
- data/.contexts/code_comment.rb +5 -8
- data/.contexts/lib.rb +0 -2
- data/CHANGES.md +12 -0
- data/README.md +158 -6
- data/Rakefile +19 -16
- data/examples/let.rb +8 -40
- data/examples/mail.rb +0 -1
- data/examples/turing.rb +3 -1
- data/lib/tins/alias.rb +1 -0
- data/lib/tins/annotate.rb +37 -27
- data/lib/tins/ask_and_send.rb +41 -0
- data/lib/tins/attempt.rb +39 -0
- data/lib/tins/bijection.rb +34 -0
- data/lib/tins/case_predicate.rb +21 -0
- data/lib/tins/complete.rb +16 -0
- data/lib/tins/concern.rb +64 -0
- data/lib/tins/date_dummy.rb +36 -4
- data/lib/tins/date_time_dummy.rb +34 -2
- data/lib/tins/deep_dup.rb +9 -2
- data/lib/tins/deprecate.rb +12 -0
- data/lib/tins/dslkit.rb +559 -83
- data/lib/tins/duration.rb +120 -5
- data/lib/tins/expose.rb +54 -5
- data/lib/tins/extract_last_argument_options.rb +9 -0
- data/lib/tins/file_binary.rb +104 -21
- data/lib/tins/find.rb +114 -11
- data/lib/tins/generator.rb +10 -2
- data/lib/tins/go.rb +81 -4
- data/lib/tins/hash_bfs.rb +4 -2
- data/lib/tins/hash_symbolize_keys_recursive.rb +62 -4
- data/lib/tins/hash_union.rb +47 -2
- data/lib/tins/if_predicate.rb +31 -0
- data/lib/tins/implement.rb +50 -0
- data/lib/tins/limited.rb +54 -5
- data/lib/tins/lines_file.rb +81 -2
- data/lib/tins/lru_cache.rb +54 -17
- data/lib/tins/memoize.rb +86 -58
- data/lib/tins/method_description.rb +87 -4
- data/lib/tins/minimize.rb +39 -11
- data/lib/tins/module_group.rb +27 -2
- data/lib/tins/named_set.rb +20 -0
- data/lib/tins/null.rb +86 -15
- data/lib/tins/once.rb +61 -4
- data/lib/tins/p.rb +44 -8
- data/lib/tins/partial_application.rb +66 -7
- data/lib/tins/proc_compose.rb +58 -1
- data/lib/tins/proc_prelude.rb +97 -10
- data/lib/tins/range_plus.rb +30 -2
- data/lib/tins/require_maybe.rb +36 -0
- data/lib/tins/responding.rb +39 -0
- data/lib/tins/secure_write.rb +24 -4
- data/lib/tins/sexy_singleton.rb +45 -48
- data/lib/tins/string_byte_order_mark.rb +33 -2
- data/lib/tins/string_camelize.rb +31 -2
- data/lib/tins/string_underscore.rb +33 -2
- data/lib/tins/string_version.rb +179 -10
- data/lib/tins/subhash.rb +35 -10
- data/lib/tins/temp_io.rb +7 -0
- data/lib/tins/temp_io_enum.rb +19 -0
- data/lib/tins/terminal.rb +31 -9
- data/lib/tins/thread_local.rb +67 -5
- data/lib/tins/time_dummy.rb +46 -21
- data/lib/tins/to.rb +15 -0
- data/lib/tins/to_proc.rb +17 -4
- data/lib/tins/token.rb +56 -1
- data/lib/tins/unit.rb +288 -149
- data/lib/tins/version.rb +1 -1
- data/lib/tins/write.rb +14 -3
- data/lib/tins/xt/blank.rb +81 -2
- data/lib/tins/xt/concern.rb +51 -0
- data/lib/tins/xt/full.rb +56 -11
- data/lib/tins/xt/irb.rb +46 -2
- data/lib/tins/xt/method_description.rb +0 -12
- data/lib/tins/xt/minimize.rb +7 -0
- data/lib/tins/xt/named.rb +71 -16
- data/lib/tins/xt/proc_compose.rb +4 -0
- data/lib/tins/xt/subhash.rb +11 -0
- data/lib/tins/xt/time_freezer.rb +43 -6
- data/lib/tins/xt.rb +1 -3
- data/lib/tins.rb +16 -3
- data/tests/duration_test.rb +4 -0
- data/tests/from_module_test.rb +30 -2
- data/tests/implement_test.rb +6 -8
- data/tests/lines_file_test.rb +2 -0
- data/tests/lru_cache_test.rb +12 -0
- data/tests/method_description_test.rb +14 -20
- data/tests/partial_application_test.rb +4 -0
- data/tests/proc_prelude_test.rb +1 -1
- data/tests/scope_test.rb +1 -1
- data/tests/string_version_test.rb +2 -0
- data/tests/to_test.rb +6 -6
- data/tins.gemspec +9 -9
- metadata +23 -41
- data/lib/tins/count_by.rb +0 -21
- data/lib/tins/deep_const_get.rb +0 -64
- data/lib/tins/timed_cache.rb +0 -51
- data/lib/tins/uniq_by.rb +0 -23
- data/lib/tins/xt/count_by.rb +0 -7
- data/lib/tins/xt/deep_const_get.rb +0 -7
- data/lib/tins/xt/uniq_by.rb +0 -25
- data/tests/count_by_test.rb +0 -17
- data/tests/deep_const_get_test.rb +0 -37
- data/tests/uniq_by_test.rb +0 -31
- /data/{COPYING → LICENSE} +0 -0
data/lib/tins/xt/concern.rb
CHANGED
@@ -1,19 +1,70 @@
|
|
1
1
|
require 'tins/concern'
|
2
2
|
|
3
3
|
module Tins
|
4
|
+
# Concern provides a mechanism for module configuration that persists across
|
5
|
+
# inheritance and inclusion boundaries using thread-local storage.
|
6
|
+
#
|
7
|
+
# This module implements a pattern where modules can be configured with
|
8
|
+
# arguments that are then available throughout the module's lifecycle in
|
9
|
+
# a thread-safe manner. It's particularly useful for implementing
|
10
|
+
# configuration-based concerns that need to maintain state across
|
11
|
+
# different scopes.
|
12
|
+
#
|
13
|
+
# @example Configured concern usage
|
14
|
+
# module MyConcern
|
15
|
+
# extend Tins::Concern
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # Configure the concern with parameters
|
19
|
+
# include MyConcern.tins_concern_configure(:option1, :option2)
|
4
20
|
module Concern
|
21
|
+
# ModuleMixin provides thread-local storage for concern configuration.
|
22
|
+
#
|
23
|
+
# This mixin adds methods to any module that includes it, allowing for
|
24
|
+
# configuration of concerns through thread-local storage. The configuration
|
25
|
+
# is stored in the current thread's context and persists during the
|
26
|
+
# execution of code that uses this concern.
|
27
|
+
#
|
28
|
+
# @note This implementation relies on Thread.current which makes it
|
29
|
+
# thread-safe but scoped to individual threads.
|
5
30
|
module ModuleMixin
|
31
|
+
# Configures the module with the given arguments and returns self.
|
32
|
+
#
|
33
|
+
# This method stores the provided arguments in thread-local storage,
|
34
|
+
# making them available via {tins_concern_args}. It's designed to be
|
35
|
+
# chainable (returns self).
|
36
|
+
#
|
37
|
+
# @param args [Array] Arguments to configure this concern with
|
38
|
+
# @return [Module] The module itself, for chaining
|
39
|
+
# @example
|
40
|
+
# MyConcern.tins_concern_configure(:option1, :option2)
|
6
41
|
def tins_concern_configure(*args)
|
7
42
|
Thread.current[:tin_concern_args] = args
|
8
43
|
self
|
9
44
|
end
|
10
45
|
|
46
|
+
# Retrieves the current concern configuration arguments.
|
47
|
+
#
|
48
|
+
# This method fetches the arguments that were previously set using
|
49
|
+
# {tins_concern_configure}. If no configuration has been set, it returns
|
50
|
+
# nil.
|
51
|
+
#
|
52
|
+
# @return [Array, nil] The stored configuration arguments or nil
|
53
|
+
# @example
|
54
|
+
# MyConcern.tins_concern_configure(:option1, :option2)
|
55
|
+
# puts MyConcern.tins_concern_args # => [:option1, :option2]
|
11
56
|
def tins_concern_args
|
12
57
|
Thread.current[:tin_concern_args]
|
13
58
|
end
|
14
59
|
end
|
15
60
|
end
|
16
61
|
|
62
|
+
# Extends the core Module class with the concern functionality.
|
63
|
+
#
|
64
|
+
# This line makes the concern configuration methods available to all modules
|
65
|
+
# in the system, allowing any module to be configured as a concern.
|
66
|
+
#
|
67
|
+
# @see Tins::Concern::ModuleMixin
|
17
68
|
class ::Module
|
18
69
|
include Tins::Concern::ModuleMixin
|
19
70
|
end
|
data/lib/tins/xt/full.rb
CHANGED
@@ -1,18 +1,51 @@
|
|
1
1
|
require 'tins/xt/blank'
|
2
2
|
|
3
3
|
module Tins
|
4
|
+
# Provides methods for checking if objects are "full" (non-blank) and safely
|
5
|
+
# processing them in conditional contexts.
|
6
|
+
#
|
7
|
+
# This module adds the `full?` and `all_full?` methods to all objects, enabling
|
8
|
+
# clean, readable patterns for validation and conditional processing.
|
9
|
+
#
|
10
|
+
# @example Basic usage
|
11
|
+
# "hello".full? # => "hello"
|
12
|
+
# "".full? # => nil
|
13
|
+
#
|
14
|
+
# @example Method dispatch with block
|
15
|
+
# user.full?(:name) { |name| "Hello #{name}" } # Returns "Hello John" if name is full
|
16
|
+
#
|
17
|
+
# @example Safe assignment and processing
|
18
|
+
# if name = user.full?(:name)
|
19
|
+
# puts "Hello #{name}"
|
20
|
+
# end
|
4
21
|
module Full
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
22
|
+
# Checks if the object is not blank, returning the object itself if it's
|
23
|
+
# full, or nil if it's blank. If a method name is provided as +dispatch+,
|
24
|
+
# that method is called on the object and the result is checked for being
|
25
|
+
# full.
|
26
|
+
#
|
27
|
+
# @param dispatch [Symbol, nil] The method to call on the object (optional)
|
28
|
+
# @param args [Array] Arguments to pass to the dispatched method (optional)
|
29
|
+
# @yield [Object] Optional block to execute with the result if result or
|
30
|
+
# dispatched result not nil
|
31
|
+
# @return [Object, nil] The object itself if not blank, or the result of
|
32
|
+
# dispatching +dispatch+ if provided and valid, or nil if the object is blank
|
33
|
+
#
|
34
|
+
# @example Basic usage
|
35
|
+
# "hello".full? # => "hello"
|
36
|
+
# "".full? # => nil
|
37
|
+
#
|
38
|
+
# @example Method dispatch
|
39
|
+
# user.full?(:name) # Returns user.name if not blank, nil otherwise
|
40
|
+
#
|
41
|
+
# @example Method dispatch with arguments
|
42
|
+
# user.full?(:method_with_args, arg1, arg2)
|
43
|
+
#
|
44
|
+
# @example With block execution
|
45
|
+
# user.full?(:name) { |name| "Hello #{name}" }
|
11
46
|
def full?(dispatch = nil, *args)
|
12
47
|
if blank?
|
13
48
|
obj = nil
|
14
|
-
#elsif Module === dispatch # TODO
|
15
|
-
# dispatch.found?(self)
|
16
49
|
elsif dispatch
|
17
50
|
obj = __send__(dispatch, *args)
|
18
51
|
obj = nil if obj.blank?
|
@@ -26,14 +59,26 @@ module Tins
|
|
26
59
|
end
|
27
60
|
end
|
28
61
|
|
62
|
+
# Checks if all elements in a collection are "full" (not blank). If the
|
63
|
+
# object responds to +all?+ and all elements pass the +full?+ test, then
|
64
|
+
# the block is executed with the collection itself or the collection is returned.
|
65
|
+
#
|
66
|
+
# @return [Object, nil] The collection if all elements are full, otherwise nil
|
67
|
+
#
|
68
|
+
# @example Basic usage
|
69
|
+
# [1,2,3].all_full? # => [1,2,3]
|
70
|
+
# [1,nil,3].all_full? # => nil
|
71
|
+
#
|
72
|
+
# @example With block execution
|
73
|
+
# [1,2,3].all_full? { |array| array.sum }
|
29
74
|
def all_full?
|
30
75
|
if respond_to?(:all?) && all?(&:full?)
|
31
76
|
block_given? ? yield(self) : self
|
32
77
|
end
|
33
78
|
end
|
34
|
-
end
|
35
79
|
|
36
|
-
|
37
|
-
|
80
|
+
class ::Object
|
81
|
+
include Full
|
82
|
+
end
|
38
83
|
end
|
39
84
|
end
|
data/lib/tins/xt/irb.rb
CHANGED
@@ -1,9 +1,42 @@
|
|
1
1
|
require 'irb'
|
2
2
|
|
3
|
+
# Provides interactive debugging capabilities through the IRB console.
|
4
|
+
#
|
5
|
+
# This module adds an `examine` method to all objects, allowing developers to
|
6
|
+
# quickly drop into an interactive IRB session with the current binding or
|
7
|
+
# examine specific objects. It's particularly useful for debugging and exploring
|
8
|
+
# data structures during development.
|
9
|
+
#
|
10
|
+
# @example Basic usage
|
11
|
+
# # Drop into IRB with current context
|
12
|
+
# examine
|
13
|
+
#
|
14
|
+
# @example Examine a specific object
|
15
|
+
# data = [1, 2, 3]
|
16
|
+
# examine data # Inspects just the 'data' variable
|
17
|
+
#
|
18
|
+
# @example Use from within methods
|
19
|
+
# def process_data
|
20
|
+
# result = expensive_operation
|
21
|
+
# examine result # Debug the result immediately
|
22
|
+
# end
|
3
23
|
module Tins
|
24
|
+
# We have our own IRB as well.
|
4
25
|
IRB = ::IRB
|
5
26
|
|
27
|
+
# We extend the top level IRB module
|
6
28
|
module ::IRB
|
29
|
+
# Starts an interactive IRB session with the given binding context. This
|
30
|
+
# method creates a new IRB instance and evaluates input from it, allowing for
|
31
|
+
# interactive exploration of variables and objects.
|
32
|
+
#
|
33
|
+
# @param binding [Binding, nil] The binding context to examine (defaults to TOPLEVEL_BINDING)
|
34
|
+
#
|
35
|
+
# @example Start IRB with current context
|
36
|
+
# examine
|
37
|
+
#
|
38
|
+
# @example Examine specific binding
|
39
|
+
# examine some_binding
|
7
40
|
def self.examine(binding = TOPLEVEL_BINDING)
|
8
41
|
setup nil
|
9
42
|
workspace = WorkSpace.new binding
|
@@ -13,9 +46,20 @@ module Tins
|
|
13
46
|
rescue Interrupt
|
14
47
|
exit
|
15
48
|
end
|
16
|
-
end
|
17
49
|
|
18
|
-
|
50
|
+
# Starts an interactive IRB session examining the current object and its context.
|
51
|
+
# This instance method provides a convenient way to debug objects without
|
52
|
+
# explicitly passing bindings.
|
53
|
+
#
|
54
|
+
# @param binding [Binding, nil] The binding context to examine (defaults to TOPLEVEL_BINDING)
|
55
|
+
# @return [void]
|
56
|
+
#
|
57
|
+
# @example Examine the current object
|
58
|
+
# my_object.examine
|
59
|
+
#
|
60
|
+
# @example Examine a specific variable
|
61
|
+
# data = [1, 2, 3]
|
62
|
+
# data.examine # Inspects just the 'data' variable
|
19
63
|
def examine(binding = TOPLEVEL_BINDING)
|
20
64
|
IRB.examine(binding)
|
21
65
|
end
|
@@ -3,21 +3,9 @@ require 'tins/method_description'
|
|
3
3
|
module Tins
|
4
4
|
class ::UnboundMethod
|
5
5
|
include MethodDescription
|
6
|
-
|
7
|
-
alias to_s description
|
8
|
-
|
9
|
-
def inspect
|
10
|
-
"#<#{self.class}: #{description}>"
|
11
|
-
end
|
12
6
|
end
|
13
7
|
|
14
8
|
class ::Method
|
15
9
|
include MethodDescription
|
16
|
-
|
17
|
-
alias to_s description
|
18
|
-
|
19
|
-
def inspect
|
20
|
-
"#<#{self.class}: #{description}>"
|
21
|
-
end
|
22
10
|
end
|
23
11
|
end
|
data/lib/tins/xt/named.rb
CHANGED
@@ -1,23 +1,78 @@
|
|
1
|
-
|
1
|
+
module Tins
|
2
|
+
# A dynamically created module class used internally by the
|
3
|
+
# {Tins::Object#named} and {Tins::Module#named} methods to create dynamic
|
4
|
+
# methods.
|
5
|
+
#
|
6
|
+
# This class inherits from Module and serves as a template for creating
|
7
|
+
# dynamically scoped methods that can be extended or included into objects
|
8
|
+
# or classes.
|
9
|
+
Named = ::Class.new(::Module)
|
2
10
|
|
3
|
-
class Object
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
11
|
+
class ::Object
|
12
|
+
# Adds a dynamically created method to the object instance. The method will
|
13
|
+
# call the specified +method+ with optional +args+ and combine any provided
|
14
|
+
# +named_block+ with runtime blocks.
|
15
|
+
#
|
16
|
+
# @param name [Symbol] The name of the method to create
|
17
|
+
# @param method [Symbol] The existing method to delegate to
|
18
|
+
# @param args [Array] Optional arguments to pre-bind to the delegated method
|
19
|
+
# @yield [Object] Optional block to be used as the method's block
|
20
|
+
# @return [Object] self
|
21
|
+
# @example Create a method that maps elements
|
22
|
+
# a = [1, 2, 3]
|
23
|
+
# a.named(:double, :map) { |x| x * 2 }
|
24
|
+
# a.double # => [2, 4, 6]
|
25
|
+
#
|
26
|
+
# @example Pre-bind arguments to a method
|
27
|
+
# def process(data, multiplier, &block)
|
28
|
+
# data.map { |x| block.call(x * multiplier) }
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# Object.named(:process_by_10, :process, 10) do |result|
|
32
|
+
# result + 1
|
33
|
+
# end
|
34
|
+
# process_by_10([1, 2, 3]) { |x| x * 2 } # => [21, 41, 61]
|
35
|
+
def named(name, method, *args, &named_block)
|
36
|
+
name = name.to_sym
|
37
|
+
m = Tins::Named.new {
|
38
|
+
define_method(name) do |*rest, &block|
|
39
|
+
block = named_block if named_block
|
40
|
+
__send__(method, *(args + rest), &block)
|
41
|
+
end
|
42
|
+
}
|
43
|
+
if m.respond_to?(:set_temporary_name)
|
44
|
+
m.set_temporary_name "#{m.class} for method #{name.inspect}"
|
9
45
|
end
|
10
|
-
|
46
|
+
extend m
|
47
|
+
end
|
11
48
|
end
|
12
|
-
end
|
13
49
|
|
14
|
-
class Module
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
50
|
+
class ::Module
|
51
|
+
# Adds a dynamically created method to all instances of the class. The
|
52
|
+
# method will call the specified +method+ with optional +args+ and combine
|
53
|
+
# any provided +named_block+ with runtime blocks.
|
54
|
+
#
|
55
|
+
# @param name [Symbol] The name of the method to create
|
56
|
+
# @param method [Symbol] The existing method to delegate to
|
57
|
+
# @param args [Array] Optional arguments to pre-bind to the delegated method
|
58
|
+
# @yield [Object] Optional block to be used as the method's block
|
59
|
+
# @return [Module] self
|
60
|
+
#
|
61
|
+
# @example Create a class-level method
|
62
|
+
# Array.named(:sum_all, :reduce) { |acc, x| acc + x }
|
63
|
+
# [1, 2, 3].sum_all # => 6
|
64
|
+
def named(name, method, *args, &named_block)
|
65
|
+
name = name.to_sym
|
66
|
+
m = Tins::Named.new {
|
67
|
+
define_method(name) do |*rest, &block|
|
68
|
+
block = named_block if named_block
|
69
|
+
__send__(method, *(args + rest), &block)
|
70
|
+
end
|
71
|
+
}
|
72
|
+
if m.respond_to?(:set_temporary_name)
|
73
|
+
m.set_temporary_name "#{m.class} for method #{name.inspect}"
|
20
74
|
end
|
21
|
-
|
75
|
+
include m
|
76
|
+
end
|
22
77
|
end
|
23
78
|
end
|
data/lib/tins/xt/proc_compose.rb
CHANGED
data/lib/tins/xt/subhash.rb
CHANGED
@@ -4,6 +4,17 @@ module Tins
|
|
4
4
|
class ::Hash
|
5
5
|
include Tins::Subhash
|
6
6
|
|
7
|
+
# The subhash! method creates a filtered subset of this hash based on the
|
8
|
+
# given patterns and replaces the current hash with the result.
|
9
|
+
#
|
10
|
+
# This method works by first calling subhash with the provided patterns to
|
11
|
+
# create a new hash containing only the matching key-value pairs, then
|
12
|
+
# replacing the contents of the current hash with those pairs.
|
13
|
+
#
|
14
|
+
# @param patterns [Array<Object>] One or more patterns to match against
|
15
|
+
# keys
|
16
|
+
# @return [Hash] Returns self after replacing its contents with the
|
17
|
+
# filtered subset
|
7
18
|
def subhash!(*patterns)
|
8
19
|
replace subhash(*patterns)
|
9
20
|
end
|
data/lib/tins/xt/time_freezer.rb
CHANGED
@@ -2,12 +2,49 @@ require 'tins/xt/time_dummy'
|
|
2
2
|
require 'tins/xt/date_time_dummy'
|
3
3
|
require 'tins/xt/date_dummy'
|
4
4
|
|
5
|
-
module Tins
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
module Tins
|
6
|
+
# TimeFreezer provides a mechanism to temporarily freeze time across multiple
|
7
|
+
# time-related classes.
|
8
|
+
#
|
9
|
+
# This module allows you to temporarily replace the behavior of Time, DateTime,
|
10
|
+
# and Date classes with dummy implementations that always return a specific
|
11
|
+
# time value. This is particularly useful for testing code that depends on
|
12
|
+
# current time values.
|
13
|
+
#
|
14
|
+
# @example Basic usage
|
15
|
+
# Tins::TimeFreezer.freeze(Time.new(2023, 1, 1)) do
|
16
|
+
# # All Time, DateTime, and Date calls will return the frozen time
|
17
|
+
# puts Time.now # => 2023-01-01 00:00:00 +0000
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @example With DateTime and Date
|
21
|
+
# Tins::TimeFreezer.freeze(Time.new(2023, 1, 1)) do
|
22
|
+
# puts DateTime.now # => 2023-01-01T00:00:00+00:00
|
23
|
+
# puts Date.today # => 2023-01-01
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @example Using time string (will be parsed by Time.parse)
|
27
|
+
# Tins::TimeFreezer.freeze("2023-01-01 12:00:00") do
|
28
|
+
# # Time.now will return the parsed time
|
29
|
+
# puts Time.now # => 2023-01-01 12:00:00 +0000
|
30
|
+
# end
|
31
|
+
module TimeFreezer
|
32
|
+
# Freezes time for the duration of the given block.
|
33
|
+
#
|
34
|
+
# This method temporarily replaces the behavior of Time, DateTime, and Date
|
35
|
+
# classes with dummy implementations that always return the specified time
|
36
|
+
# value.
|
37
|
+
#
|
38
|
+
# @param time [Time, DateTime, Date] The time value to freeze all
|
39
|
+
# time-related classes to
|
40
|
+
# @yield [] The block of code to execute with frozen time
|
41
|
+
# @return [Object] The return value of the yielded block
|
42
|
+
def self.freeze(time)
|
43
|
+
Time.dummy(time) do
|
44
|
+
DateTime.dummy(time) do
|
45
|
+
Date.dummy(time) do
|
46
|
+
yield
|
47
|
+
end
|
11
48
|
end
|
12
49
|
end
|
13
50
|
end
|
data/lib/tins/xt.rb
CHANGED
@@ -3,7 +3,6 @@ require 'tins'
|
|
3
3
|
module Tins
|
4
4
|
require 'tins/xt/attempt'
|
5
5
|
require 'tins/xt/blank'
|
6
|
-
require 'tins/xt/count_by'
|
7
6
|
require 'tins/xt/deep_dup'
|
8
7
|
require 'tins/xt/file_binary'
|
9
8
|
require 'tins/xt/full'
|
@@ -22,12 +21,10 @@ module Tins
|
|
22
21
|
require 'tins/xt/time_dummy'
|
23
22
|
require 'tins/xt/date_dummy'
|
24
23
|
require 'tins/xt/date_time_dummy'
|
25
|
-
require 'tins/xt/uniq_by'
|
26
24
|
require 'tins/xt/write'
|
27
25
|
require 'tins/xt/if_predicate'
|
28
26
|
require 'tins/xt/ask_and_send'
|
29
27
|
require 'tins/xt/extract_last_argument_options'
|
30
|
-
require 'tins/xt/deep_const_get'
|
31
28
|
require 'tins/xt/responding'
|
32
29
|
require 'tins/xt/proc_compose'
|
33
30
|
require 'tins/xt/proc_prelude'
|
@@ -44,4 +41,5 @@ module Tins
|
|
44
41
|
require 'tins/xt/temp_io'
|
45
42
|
require 'tins/xt/deprecate'
|
46
43
|
require 'tins/xt/hash_bfs'
|
44
|
+
require 'tins/xt/minimize'
|
47
45
|
end
|
data/lib/tins.rb
CHANGED
@@ -1,7 +1,22 @@
|
|
1
|
+
# Tins is a collection of useful Ruby utilities and tools that provide
|
2
|
+
# common functionality without requiring external dependencies. It's designed
|
3
|
+
# to be a lightweight, drop-in library that enhances Ruby's standard library
|
4
|
+
# with practical conveniences.
|
5
|
+
#
|
6
|
+
# @example Basic usage
|
7
|
+
# require 'tins'
|
8
|
+
#
|
9
|
+
# Tins::Once.only_once { puts "Only one instance" }
|
10
|
+
#
|
11
|
+
# @example Automatic class extensions
|
12
|
+
# require 'tins/xt'
|
13
|
+
#
|
14
|
+
# # Automatically extends core classes with useful methods
|
15
|
+
# "foo".full? # => "foo"
|
16
|
+
# " ".full? # => nil
|
1
17
|
module Tins
|
2
18
|
require 'tins/attempt'
|
3
19
|
require 'tins/bijection'
|
4
|
-
require 'tins/count_by'
|
5
20
|
require 'tins/deep_dup'
|
6
21
|
require 'tins/file_binary'
|
7
22
|
require 'tins/find'
|
@@ -31,11 +46,9 @@ module Tins
|
|
31
46
|
require 'tins/date_dummy'
|
32
47
|
require 'tins/date_time_dummy'
|
33
48
|
require 'tins/to_proc'
|
34
|
-
require 'tins/uniq_by'
|
35
49
|
require 'tins/version'
|
36
50
|
require 'tins/write'
|
37
51
|
require 'tins/extract_last_argument_options'
|
38
|
-
require 'tins/deep_const_get'
|
39
52
|
require 'tins/responding'
|
40
53
|
require 'tins/proc_compose'
|
41
54
|
require 'tins/proc_prelude'
|
data/tests/duration_test.rb
CHANGED
@@ -22,6 +22,10 @@ module Tins
|
|
22
22
|
assert_equal '0+00:11:06.123456', Tins::Duration.new(666.123456).format
|
23
23
|
end
|
24
24
|
|
25
|
+
def test_format_percentage
|
26
|
+
assert_equal '11%06', Tins::Duration.new(666.123456).format('%m%%%s')
|
27
|
+
end
|
28
|
+
|
25
29
|
def test_smart_format
|
26
30
|
assert_equal '00:11:06.123', Tins::Duration.new(666.123456).format('%D')
|
27
31
|
assert_equal '7+17:11:06.123', Tins::Duration.new(666666.123456).format('%D')
|
data/tests/from_module_test.rb
CHANGED
@@ -11,6 +11,16 @@ class FromModuleTest < Test::Unit::TestCase
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
module MyIncludedModule2
|
15
|
+
def foo
|
16
|
+
:foo2
|
17
|
+
end
|
18
|
+
|
19
|
+
def bar
|
20
|
+
:bar2
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
14
24
|
class MyKlass
|
15
25
|
def foo
|
16
26
|
:original_foo
|
@@ -35,14 +45,17 @@ class FromModuleTest < Test::Unit::TestCase
|
|
35
45
|
def bar
|
36
46
|
:original_bar
|
37
47
|
end
|
48
|
+
|
49
|
+
def baz
|
50
|
+
:original_baz
|
51
|
+
end
|
38
52
|
include MyIncludedModule
|
39
53
|
end
|
40
54
|
|
41
55
|
class AnotherDerivedKlass
|
42
|
-
include MyModule
|
43
|
-
|
44
56
|
extend Tins::FromModule
|
45
57
|
|
58
|
+
include MyModule
|
46
59
|
include from module: MyIncludedModule, methods: :foo
|
47
60
|
end
|
48
61
|
|
@@ -57,4 +70,19 @@ class FromModuleTest < Test::Unit::TestCase
|
|
57
70
|
assert_equal :foo, c.foo
|
58
71
|
assert_equal :original_bar, c.bar
|
59
72
|
end
|
73
|
+
|
74
|
+
class MixedClass
|
75
|
+
extend Tins::FromModule
|
76
|
+
|
77
|
+
include MyModule
|
78
|
+
include from module: MyIncludedModule, methods: :foo
|
79
|
+
include from module: MyIncludedModule2, methods: :bar
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_mixed_klass
|
83
|
+
c = MixedClass.new
|
84
|
+
assert_equal :foo, c.foo
|
85
|
+
assert_equal :bar2, c.bar
|
86
|
+
assert_equal :original_baz, c.baz
|
87
|
+
end
|
60
88
|
end
|
data/tests/implement_test.rb
CHANGED
@@ -53,14 +53,12 @@ module Tins
|
|
53
53
|
assert_equal('blab', error_message { A.new.quux })
|
54
54
|
end
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
)
|
63
|
-
end
|
56
|
+
def test_implement_def_subclass
|
57
|
+
assert_equal(
|
58
|
+
'method foobar(arg1,arg2:…) has to be '\
|
59
|
+
'implemented in subclasses of Tins::ImplementTest::A',
|
60
|
+
error_message { A.new.foobar }
|
61
|
+
)
|
64
62
|
end
|
65
63
|
|
66
64
|
private
|
data/tests/lines_file_test.rb
CHANGED
data/tests/lru_cache_test.rb
CHANGED
@@ -6,6 +6,18 @@ module Tins
|
|
6
6
|
@cache = LRUCache.new(3)
|
7
7
|
end
|
8
8
|
|
9
|
+
def test_too_low_capacity
|
10
|
+
assert_raise ArgumentError do
|
11
|
+
LRUCache.new(0)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_wrong_capacity_type
|
16
|
+
assert_raise TypeError do
|
17
|
+
LRUCache.new(:foo)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
9
21
|
def test_can_be_filled_to_capacity
|
10
22
|
assert_equal 0, @cache.size
|
11
23
|
@cache[1] = 1
|
@@ -12,10 +12,8 @@ module Tins
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_static_nonstatic
|
15
|
-
assert_equal 'Tins::MethodDescriptionTest::A#foo()', A.instance_method(:foo).
|
16
|
-
assert_equal '
|
17
|
-
assert_equal 'Tins::MethodDescriptionTest::A.foo()', A.method(:foo).to_s
|
18
|
-
assert_equal '#<Method: Tins::MethodDescriptionTest::A.foo()>', A.method(:foo).inspect
|
15
|
+
assert_equal 'Tins::MethodDescriptionTest::A#foo()', A.instance_method(:foo).description
|
16
|
+
assert_equal 'Tins::MethodDescriptionTest::A.foo()', A.method(:foo).description
|
19
17
|
end
|
20
18
|
|
21
19
|
class B
|
@@ -33,12 +31,12 @@ module Tins
|
|
33
31
|
end
|
34
32
|
|
35
33
|
def test_standard_parameters_namespace
|
36
|
-
assert_equal 'Tins::MethodDescriptionTest::B#foo(x,y
|
37
|
-
B.instance_method(:foo).
|
34
|
+
assert_equal 'Tins::MethodDescriptionTest::B#foo(x,y=…,*r,&b)',
|
35
|
+
B.instance_method(:foo).description
|
38
36
|
end
|
39
37
|
|
40
38
|
def test_standard_parameters_name
|
41
|
-
assert_equal 'foo(x,y
|
39
|
+
assert_equal 'foo(x,y=…,*r,&b)',
|
42
40
|
B.instance_method(:foo).description(style: :name)
|
43
41
|
end
|
44
42
|
|
@@ -84,21 +82,17 @@ module Tins
|
|
84
82
|
end
|
85
83
|
|
86
84
|
def test_keyword_parameters
|
87
|
-
assert_equal 'Tins::MethodDescriptionTest::C#foo(x,k
|
88
|
-
assert_equal 'Tins::MethodDescriptionTest::C#bar(x,**k,&b)', C.instance_method(:bar).
|
85
|
+
assert_equal 'Tins::MethodDescriptionTest::C#foo(x,k:…,&b)', C.instance_method(:foo).description
|
86
|
+
assert_equal 'Tins::MethodDescriptionTest::C#bar(x,**k,&b)', C.instance_method(:bar).description
|
89
87
|
end
|
90
88
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
def test_keyword_parameters_required
|
99
|
-
assert_equal 'Tins::MethodDescriptionTest::D#foo(x,k:,&b)', D.instance_method(:foo).to_s
|
100
|
-
end
|
101
|
-
}
|
89
|
+
class D
|
90
|
+
def foo(x, k:, &b)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_keyword_parameters_required
|
95
|
+
assert_equal 'Tins::MethodDescriptionTest::D#foo(x,k:,&b)', D.instance_method(:foo).description
|
102
96
|
end
|
103
97
|
end
|
104
98
|
end
|