minitwin 1.0.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.
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ class Minitwin
5
+ module Sync
6
+ # Cache constant reference for JIT optimization
7
+ MODEL_PREFIX = Minitwin::INTERNAL_MODEL_PREFIX
8
+
9
+ #: (untyped, validate: bool) -> bool
10
+ def sync(model = nil, validate: true)
11
+ # Resolve target model
12
+ target_model = model
13
+ if target_model.nil?
14
+ ivar = self.class.internal_model_name("model")
15
+ target_model = instance_variable_defined?(ivar) ? instance_variable_get(ivar) : nil
16
+ if target_model.nil?
17
+ any_ivar = instance_variables.find { |v| v.to_s.start_with?(MODEL_PREFIX) }
18
+ target_model = instance_variable_get(any_ivar) if any_ivar
19
+ end
20
+ end
21
+
22
+ return false if validate && !valid?
23
+ return false if target_model.nil?
24
+
25
+ attribute_methods.each do |method_name| # rubocop: disable Metrics/BlockLength
26
+ prop_meta = self.class.properties[method_name] || self.class.collections[method_name]
27
+ as_name = prop_meta&.[](:as)
28
+ target_name = as_name.is_a?(Symbol) || as_name.is_a?(String) ? as_name.to_sym : method_name
29
+
30
+ writer = :"#{target_name}="
31
+ next unless target_model.respond_to?(writer) || target_model.respond_to?(target_name)
32
+
33
+ value = respond_to?(method_name, true) ? send(method_name) : nil
34
+
35
+ # Nested twins
36
+ if value.is_a?(Minitwin)
37
+ if target_model.respond_to?(target_name)
38
+ begin
39
+ child_model = target_model.public_send(target_name)
40
+ if child_model
41
+ value.sync(child_model, validate: false)
42
+ next
43
+ end
44
+ rescue StandardError
45
+ # fall through to writer
46
+ end
47
+ end
48
+ elsif value.is_a?(Array)
49
+ if target_model.respond_to?(target_name)
50
+ begin
51
+ coll = target_model.public_send(target_name)
52
+ if coll.respond_to?(:each)
53
+ deep_synced_any = false
54
+
55
+ id_map = build_target_id_lookup(coll)
56
+
57
+ value.each_with_index do |elem, idx|
58
+ next unless elem.is_a?(Minitwin)
59
+
60
+ target = nil
61
+
62
+ # Try id-based match first
63
+ target ||= begin
64
+ elem_id = elem.respond_to?(:id, true) ? elem.send(:id) : nil
65
+ id_map && elem_id ? id_map[elem_id] : nil
66
+ end
67
+
68
+ if target.nil? && coll.respond_to?(:[])
69
+ begin
70
+ target = coll[idx]
71
+ rescue StandardError
72
+ target = nil
73
+ end
74
+ end
75
+
76
+ next unless target
77
+
78
+ elem.sync(target, validate: false)
79
+ deep_synced_any = true
80
+ next
81
+
82
+ # Unmatched elements are handled later by writer fallback
83
+ end
84
+
85
+ next if deep_synced_any
86
+ end
87
+ rescue StandardError
88
+ # continue to writer fallback
89
+ end
90
+ end
91
+ end
92
+
93
+ assignable = case value
94
+ when Minitwin
95
+ value.to_hash
96
+ when Array
97
+ value.map { |v| v.is_a?(Minitwin) ? v.to_hash : v }
98
+ else
99
+ value
100
+ end
101
+
102
+ begin
103
+ target_model.public_send(writer, assignable)
104
+ rescue StandardError
105
+ # ignore and continue
106
+ end
107
+ end
108
+
109
+ true
110
+ end
111
+
112
+ private
113
+
114
+ # Builds a lookup hash from the provided collection.
115
+ # The collection may be an array or something convertible to an array.
116
+ # The result is a hash map with the ids of the models in the collection as
117
+ # keys and the models itself as values.
118
+ def build_target_id_lookup(coll)
119
+ ary = if coll.is_a?(Array)
120
+ coll
121
+ elsif coll.respond_to?(:to_a)
122
+ coll.to_a
123
+ else
124
+ return nil
125
+ end
126
+
127
+ ary.each_with_object({}) do |m, h|
128
+ next unless m.respond_to?(:id)
129
+
130
+ key = m.id
131
+ h[key] = m if key
132
+ end
133
+ end
134
+
135
+ # No append or match_on helpers
136
+ end
137
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Minitwin
4
+ VERSION = "1.0.0"
5
+ end
data/lib/minitwin.rb ADDED
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "zeitwerk"
5
+ begin
6
+ require "dry-types"
7
+ rescue LoadError
8
+ # dry-types is an optional dependency
9
+ end
10
+ require_relative "minitwin/version"
11
+
12
+ begin
13
+ require "active_model"
14
+ rescue LoadError
15
+ # active_model is an optional dependency
16
+ end
17
+
18
+ # Setup Zeitwerk loader for the gem to support Rails autoloading
19
+ loader = Zeitwerk::Loader.for_gem
20
+ loader.setup
21
+
22
+ class Minitwin
23
+ # Constants for internal variable naming
24
+ INTERNAL_MODEL_PREFIX = "@internal_model__"
25
+ NESTED_READER_PREFIX = "__nested_read__"
26
+ DYNAMIC_ALIASES_VAR = "@__dynamic_aliases__"
27
+ DYNAMIC_ALIASES_REV_VAR = "@__dynamic_aliases_rev__"
28
+
29
+ # Shared utility methods
30
+ module Utils
31
+ module_function
32
+
33
+ # Normalize property name to instance variable name (handles ? suffix)
34
+ def ivar_name(name)
35
+ "@#{name}".delete_suffix("?")
36
+ end
37
+
38
+ # Convert instance variable to attribute key symbol
39
+ def ivar_to_key(ivar)
40
+ ivar.to_s.delete_prefix("@").to_sym
41
+ end
42
+
43
+ # Traverse a nested path on an object
44
+ def traverse_path(obj, path)
45
+ path.each { |seg| obj = obj.public_send(seg) }
46
+ obj
47
+ end
48
+ end
49
+
50
+ include ActiveModel::Model if defined?(ActiveModel::Model)
51
+ include Minitwin::Initialization
52
+ include Minitwin::Assignment
53
+ include Minitwin::Serialization
54
+ include Minitwin::Sync
55
+ extend Minitwin::ClassMethods
56
+
57
+ # Lazy-memoized lookups for late-loaded optional deps (Dry::Types,
58
+ # ActiveSupport's HashWithIndifferentAccess). Resolved on first call so
59
+ # boot-order between minitwin and the deps does not matter.
60
+ class << self
61
+ def hash_klass
62
+ @hash_klass ||= defined?(HashWithIndifferentAccess) ? HashWithIndifferentAccess : Hash
63
+ end
64
+
65
+ private
66
+
67
+ def coercion_error_classes
68
+ @coercion_error_classes ||= begin
69
+ arr = [TypeError, ArgumentError]
70
+ arr.unshift(::Dry::Types::CoercionError) if defined?(::Dry::Types::CoercionError)
71
+ arr.freeze
72
+ end
73
+ end
74
+
75
+ def active_model_initialized?(klass)
76
+ return false unless defined?(ActiveModel::API) || defined?(ActiveModel::Model)
77
+
78
+ ancestors = klass.ancestors
79
+ (defined?(ActiveModel::API) && ancestors.include?(ActiveModel::API)) ||
80
+ (defined?(ActiveModel::Model) && ancestors.include?(ActiveModel::Model))
81
+ end
82
+ end
83
+
84
+ # Track descendants via WeakMap so anonymous subclasses can be GC'd.
85
+ # The map lives only on Minitwin itself; subclasses' inherited hooks
86
+ # delegate up so that deep hierarchies still register on the root.
87
+ @__descendants_map__ = ObjectSpace::WeakMap.new
88
+ class << self
89
+ def __descendants__
90
+ Minitwin.instance_variable_get(:@__descendants_map__).keys
91
+ end
92
+
93
+ def inherited(sub)
94
+ Minitwin.instance_variable_get(:@__descendants_map__)[sub] = true
95
+ super
96
+ end
97
+ end
98
+ end
99
+
100
+ # Optional: Generate RBS on exit when configured via ENV.
101
+ if ENV["MINITWIN_RBS_OUT"] && !ENV["MINITWIN_RBS_OUT"].empty?
102
+ at_exit do
103
+ require "fileutils"
104
+ path = ENV["MINITWIN_RBS_OUT"]
105
+ begin
106
+ twins = Minitwin.__descendants__.select(&:name)
107
+ content = +""
108
+ content << "# This file is generated by minitwin. DO NOT EDIT.\n"
109
+ content << "# Generated at: #{Time.now}\n\n"
110
+ twins.sort_by!(&:name)
111
+ twins.each do |k|
112
+ content << k.to_rbs
113
+ content << "\n\n"
114
+ end
115
+ FileUtils.mkdir_p(File.dirname(path))
116
+ File.write(path, content)
117
+ rescue StandardError => exception
118
+ warn "[minitwin] Failed to generate RBS: #{exception.class}: #{exception.message}"
119
+ end
120
+ end
121
+ end
122
+
123
+ require "minitwin/railtie" if defined?(Rails::Railtie)
124
+ # Minitwin
125
+ # --------
126
+ # Entry point that wires together the core modules and conditionally enables
127
+ # ActiveModel integration when it is available. The goal is to keep runtime
128
+ # dependencies minimal while providing a clean DSL for twin/presenter objects.
129
+ # See docs/ARCHITECTURE.md for an overview.
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../minitwin"
4
+ require "fileutils"
5
+
6
+ namespace :minitwin do
7
+ desc "Generate RBS signatures for all loaded Minitwin subclasses into sig/generated/ " \
8
+ "(override output dir with OUTPUT_DIR env var or task argument)"
9
+
10
+ task :generate_rbs, [:output_dir] do |_t, args|
11
+ # In Rails, invoke :environment to ensure the app is fully initialized
12
+ # before eager loading. We invoke it here rather than declaring it as a
13
+ # prerequisite because Rails defines :environment *after* running railtie
14
+ # rake_tasks blocks, so Rake::Task.task_defined?(:environment) is always
15
+ # false at rake file load time.
16
+ Rake::Task[:environment].invoke if Rake::Task.task_defined?(:environment)
17
+
18
+ # Eager load the rails app if the task runs in Rails context
19
+ Rails.application.eager_load! if defined?(Rails)
20
+
21
+ # Require files "manually" in non-rails projects.
22
+ # Provide pattern for file paths as ENV var:
23
+ #
24
+ # MINITWIN_REQUIRE_GLOB="lib/**/*.rb" rake minitwin:generate_rbs
25
+ #
26
+ if (glob = ENV.fetch("MINITWIN_REQUIRE_GLOB", nil))
27
+ Dir[glob].each { |f| require File.expand_path(f) }
28
+ end
29
+
30
+ output_dir = args[:output_dir] || ENV.fetch("MINITWIN_RBS_DIR", "sig/generated")
31
+
32
+ twins = Minitwin.__descendants__.select(&:name).sort_by(&:name)
33
+
34
+ if twins.empty?
35
+ warn "[minitwin] No Minitwin subclasses found. " \
36
+ "Ensure your classes are loaded before running this task."
37
+ next
38
+ end
39
+
40
+ twins.each do |klass|
41
+ file_path = klass.name.
42
+ gsub("::", "/").
43
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
44
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
45
+ downcase.
46
+ concat(".rbs")
47
+
48
+ output_path = File.join(output_dir, file_path)
49
+ FileUtils.mkdir_p(File.dirname(output_path))
50
+ File.write(output_path, "# Generated by minitwin. DO NOT EDIT.\n\n#{klass.to_rbs}\n")
51
+ puts " [minitwin] #{output_path}"
52
+ end
53
+ end
54
+
55
+ desc "Check that generated RBS signatures are up to date"
56
+ task :check_rbs do
57
+ FileUtils.rm_rf(Dir["sig/generated/**/*.rbs"])
58
+ sh "bundle exec rbs-inline --output lib"
59
+
60
+ diff = `git diff --name-only sig/generated`
61
+ untracked = `git ls-files --others --exclude-standard sig/generated`
62
+
63
+ unless diff.empty? && untracked.empty?
64
+ warn "[minitwin] RBS signatures are out of date. Run: bundle exec rbs-inline --output lib"
65
+ warn diff unless diff.empty?
66
+ warn untracked unless untracked.empty?
67
+ exit 1
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,29 @@
1
+ # Generated from lib/minitwin/assignment.rb with RBS::Inline
2
+
3
+ class Minitwin
4
+ # Assign/update helpers to merge incoming data into an existing twin.
5
+ # - assign_object: copy readable attributes from an object and remember it
6
+ # - assign_hash / assign_params: update only known attributes, recursing into
7
+ # nested twins and collection items when possible
8
+ module Assignment
9
+ # Mirror values from a model's getters into this twin's setters
10
+ # : (untyped) -> instance
11
+ def to_object: (untyped) -> instance
12
+
13
+ # : (untyped) -> instance
14
+ def assign_object: (untyped) -> instance
15
+
16
+ # : (Hash[ String | Symbol, untyped ] hash) -> instance
17
+ def assign_hash: (Hash[String | Symbol, untyped] hash) -> instance
18
+
19
+ # Actually, this is expected to be an `ActionController::Parameters`
20
+ # object. The type will be unknown when used without rails. So for RBS
21
+ # the argument is typed `untyped`.
22
+ # : (untyped params) -> instance
23
+ def assign_params: (untyped params) -> instance
24
+
25
+ # Gets the non-readonly methods, which can be assigned with new values.
26
+ # : () -> Array[Symbol]
27
+ def assignable_attribute_methods: () -> Array[Symbol]
28
+ end
29
+ end
@@ -0,0 +1,40 @@
1
+ # Generated from lib/minitwin/class_methods/caches.rb with RBS::Inline
2
+
3
+ class Minitwin
4
+ module ClassMethods
5
+ module Caches
6
+ # : () -> bool
7
+ def dynamic_aliases?: () -> bool
8
+
9
+ private
10
+
11
+ def invalidate_caches: () -> untyped
12
+
13
+ def serializable_getters: () -> untyped
14
+
15
+ # Methods defined directly on the twin class hierarchy: this class and any
16
+ # intermediate Minitwin subclasses, but not Minitwin itself. Methods mixed
17
+ # in via modules (e.g. ActionView helpers, which include arg-taking methods
18
+ # like #link_to) are excluded because instance_methods(false) reports only
19
+ # methods owned by the class, not by included modules.
20
+ def serializable_method_candidates: () -> untyped
21
+
22
+ # Base names of every declared property and collection across the twin
23
+ # class hierarchy. Only methods whose declaration name is one of these
24
+ # serialize, so plain getters hand-defined on a twin are excluded. `as:`
25
+ # aliases pass because #original_name maps them back to the original
26
+ # property (the aliased reader is made protected and rejected separately).
27
+ def declared_property_keys: () -> untyped
28
+
29
+ # This class and any intermediate Minitwin subclasses, but not Minitwin
30
+ # itself or mixed-in modules.
31
+ def twin_class_hierarchy: () -> untyped
32
+
33
+ def allowed_attribute_keys: () -> untyped
34
+
35
+ def allowed_attribute_keys_array: () -> untyped
36
+
37
+ def setter_methods: () -> untyped
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ # Generated from lib/minitwin/class_methods/constructors.rb with RBS::Inline
2
+
3
+ class Minitwin
4
+ module ClassMethods
5
+ module Constructors
6
+ # : () -> Hash[untyped, untyped]
7
+ def properties: () -> Hash[untyped, untyped]
8
+
9
+ # : () -> Hash[untyped, untyped]
10
+ def collections: () -> Hash[untyped, untyped]
11
+
12
+ # : (Hash[untyped, untyped] args) -> instance
13
+ def from_hash: (Hash[untyped, untyped] args) -> instance
14
+
15
+ # : (String body) -> instance
16
+ def from_json: (String body) -> instance
17
+
18
+ # Actually, this is expected to be an `ActionController::Parameters`
19
+ # object. The type will be unknown when used without rails. So for RBS
20
+ # the argument is typed `untyped`.
21
+ # : (untyped params) -> instance
22
+ def from_params: (untyped params) -> instance
23
+
24
+ # : (untyped model) -> instance
25
+ def from_object: (untyped model) -> instance
26
+
27
+ # : (Hash[Symbol, untyped] **models) -> instance
28
+ def from_objects: (**untyped models) -> untyped
29
+
30
+ # : (Array[untyped] models) -> Array[instance]
31
+ def from_collection: (Array[untyped] models) -> Array[instance]
32
+
33
+ # : (Symbol name) -> String | nil
34
+ def internal_model_name: (Symbol name) -> String
35
+
36
+ def enrich_attributes_from_models!: (untyped attributes, untyped models) -> untyped
37
+
38
+ def enrich_attribute_from_models: (untyped attributes, untyped models, untyped key, is_collection: untyped) -> untyped
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,79 @@
1
+ # Generated from lib/minitwin/class_methods/dsl.rb with RBS::Inline
2
+
3
+ class Minitwin
4
+ module ClassMethods
5
+ module Dsl
6
+ # : () -> Array[Symbol]
7
+ def block_properties: () -> Array[Symbol]
8
+
9
+ # : () -> Array[Symbol]
10
+ def collection_properties: () -> Array[Symbol]
11
+
12
+ # : () -> Array[Symbol]
13
+ def unexposed_properties: () -> Array[Symbol]
14
+
15
+ # : () -> Array[Symbol]
16
+ def property_order: () -> Array[Symbol]
17
+
18
+ # : () -> Array[Hash]
19
+ def dynamic_nested_aliases: () -> Array[Hash]
20
+
21
+ # @rbs name: Symbol
22
+ # @rbs validates: Hash[Symbol, untyped]
23
+ # @rbs default: untyped
24
+ # @rbs as: Symbol | Proc
25
+ # @rbs getter: Proc
26
+ # @rbs twin: untyped
27
+ # @rbs on: Symbol
28
+ # @rbs return: void
29
+ def collection: (Symbol name, ?validates: Hash[Symbol, untyped], ?default: untyped, ?as: untyped, ?getter: Proc, ?twin: untyped, ?on: Symbol, **untyped _opts) ?{ (?) -> untyped } -> void
30
+
31
+ # @rbs name: Symbol
32
+ # @rbs validates: Hash[Symbol, untyped]
33
+ # @rbs default: untyped
34
+ # @rbs as: Symbol | Proc
35
+ # @rbs expose: bool
36
+ # @rbs readonly: bool
37
+ # @rbs type: untyped
38
+ # @rbs getter: Proc
39
+ # @rbs setter: Proc
40
+ # @rbs twin: untyped
41
+ # @rbs on: Symbol
42
+ # @rbs return: void
43
+ def property: (Symbol name, ?validates: Hash[Symbol, untyped], ?default: untyped, ?as: untyped, ?expose: bool, ?readonly: bool, ?type: untyped, ?getter: Proc, ?setter: Proc, ?twin: untyped, ?on: Symbol, **untyped _opts) ?{ (?) -> untyped } -> void
44
+
45
+ # @rbs name: Symbol
46
+ # @rbs as: Symbol | Proc
47
+ # @rbs return: void
48
+ def nested: (Symbol name, ?as: untyped) ?{ (?) -> untyped } -> void
49
+
50
+ private
51
+
52
+ def constantize_name: (untyped name) -> untyped
53
+
54
+ def create_nested_class: (name: untyped) ?{ (?) -> untyped } -> untyped
55
+
56
+ def define_getter_method: (name: untyped, as: untyped, on: untyped, default: untyped, getter: untyped, ?type: untyped) -> untyped
57
+
58
+ def build_getter_proc: (name: untyped, on: untyped, default: untyped, getter: untyped, type: untyped) -> untyped
59
+
60
+ def build_composition_getter: (name: untyped, on: untyped, default: untyped, type: untyped) -> untyped
61
+
62
+ def build_regular_getter: (name: untyped, default: untyped, type: untyped) -> untyped
63
+
64
+ def apply_alias_to_getter: (name: untyped, as: untyped) -> untyped
65
+
66
+ def add_validation: (name: untyped, validates: untyped) -> untyped
67
+
68
+ def add_unexposed_property: (name: untyped, expose: untyped) -> untyped
69
+
70
+ def add_block_property: (name: untyped) -> untyped
71
+
72
+ def add_collection_property: (name: untyped) -> untyped
73
+
74
+ def add_to_property_order: (untyped name) -> untyped
75
+
76
+ def resolve_default_value: (untyped default, untyped type) -> untyped
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,20 @@
1
+ # Generated from lib/minitwin/class_methods/rbs.rb with RBS::Inline
2
+
3
+ class Minitwin
4
+ module ClassMethods
5
+ module Rbs
6
+ # : () -> String
7
+ def to_rbs: () -> String
8
+
9
+ private
10
+
11
+ def rbs_type_for: (untyped meta) -> untyped
12
+
13
+ def rbs_elem_type_for: (untyped meta) -> untyped
14
+
15
+ def rbs_class_name: (untyped klass) -> untyped
16
+
17
+ def dry_type_to_rbs: (untyped dry_type) -> untyped
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ # Generated from lib/minitwin/initialization.rb with RBS::Inline
2
+
3
+ class Minitwin
4
+ # Instance construction and low-level helpers used by the DSL-generated
5
+ # accessors. Filters unknown keys on initialize and seeds nested block
6
+ # properties so that validations on nested twins can run.
7
+ module Initialization
8
+ # Cache constant references for JIT optimization
9
+ ALIASES_VAR: untyped
10
+
11
+ ALIASES_REV_VAR: untyped
12
+
13
+ # Forbidden method names that should never be aliased for security reasons
14
+ FORBIDDEN_ALIAS_NAMES: untyped
15
+
16
+ # : (**untyped) -> instance
17
+ def initialize: (**untyped) -> instance
18
+
19
+ private
20
+
21
+ def assign_attribute: (method: untyped, value: untyped) -> untyped
22
+
23
+ def attribute_methods: () -> untyped
24
+
25
+ def define_instance_variable: (name: untyped, value: untyped) -> untyped
26
+
27
+ # Define or update per-instance alias methods for properties/collections
28
+ # where `as:` was provided as a Proc. The Proc is executed in the context
29
+ # of the instance to compute the alias name.
30
+ def __recompute_dynamic_aliases__: () -> untyped
31
+
32
+ def __recompute_aliases_for_collection__: (untyped collection_method) -> untyped
33
+
34
+ def __recompute_nested_aliases__: () -> untyped
35
+
36
+ def __compute_alias_name__: (untyped as_proc) -> untyped
37
+
38
+ def __compute_nested_alias_name__: (untyped entry) -> untyped
39
+
40
+ def __apply_dynamic_alias__: (untyped target_method, untyped alias_name) -> untyped
41
+
42
+ # Public: expose current dynamic aliases as a Hash of alias_name => target_method
43
+ def dynamic_aliases: () -> untyped
44
+ end
45
+ end
@@ -0,0 +1,47 @@
1
+ # Generated from lib/minitwin/serialization.rb with RBS::Inline
2
+
3
+ class Minitwin
4
+ # Serialization to Hash/JSON and ActiveModel validation aggregation.
5
+ # Converts nested twins recursively and preserves array items (dropping only
6
+ # nil). When ActiveModel validations are available, nested errors are
7
+ # surfaced on the parent using dot/bracket notation.
8
+ module Serialization
9
+ # Cache constant references for JIT optimization
10
+ ALIASES_VAR: untyped
11
+
12
+ NESTED_PREFIX: untyped
13
+
14
+ # : (render_nil: bool) -> Hash[Symbol, untyped]
15
+ def to_hash: (render_nil: bool) -> Hash[Symbol, untyped]
16
+
17
+ alias to_h to_hash
18
+
19
+ # : (**untyped) -> String
20
+ def to_json: (**untyped) -> String
21
+
22
+ # : () -> Hash[Symbol, untyped]
23
+ def attributes: () -> Hash[Symbol, untyped]
24
+
25
+ # : () -> bool
26
+ def valid?: () -> bool
27
+
28
+ # : () -> String
29
+ def inspect: () -> String
30
+
31
+ # Internal helper for PrettyPrint. Do not call this on your own.
32
+ # : (PP) -> void
33
+ def pretty_print: (PP) -> void
34
+
35
+ private
36
+
37
+ def transform_value_for_serialization: (untyped value) -> untyped
38
+
39
+ def ordered_attributes_for_pp: () -> untyped
40
+
41
+ def ordered_methods_for_pp: () -> untyped
42
+
43
+ def display_name_for: (untyped method) -> untyped
44
+
45
+ def dynamic_aliases_for_pp: () -> untyped
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ # Generated from lib/minitwin/sync.rb with RBS::Inline
2
+
3
+ class Minitwin
4
+ module Sync
5
+ # Cache constant reference for JIT optimization
6
+ MODEL_PREFIX: untyped
7
+
8
+ # : (untyped, validate: bool) -> bool
9
+ def sync: (untyped, validate: bool) -> bool
10
+
11
+ private
12
+
13
+ # Builds a lookup hash from the provided collection.
14
+ # The collection may be an array or something convertible to an array.
15
+ # The result is a hash map with the ids of the models in the collection as
16
+ # keys and the models itself as values.
17
+ def build_target_id_lookup: (untyped coll) -> untyped
18
+ end
19
+ end
data/sig/module.rbs ADDED
@@ -0,0 +1,19 @@
1
+ # This should come from Dry Types, but they do not ship rbs signatures.
2
+
3
+ module Types
4
+ module Params
5
+ String: untyped
6
+ Nil: untyped
7
+ Date: untyped
8
+ DateTime: untyped
9
+ Time: untyped
10
+ True: untyped
11
+ False: untyped
12
+ Bool: untyped
13
+ Integer: untyped
14
+ Float: untyped
15
+ Decimal: untyped
16
+ Array: untyped
17
+ Hash: untyped
18
+ end
19
+ end