castkit 0.1.2 → 0.3.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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec_status +195 -219
  3. data/CHANGELOG.md +42 -0
  4. data/README.md +744 -83
  5. data/castkit.gemspec +1 -0
  6. data/lib/castkit/attribute.rb +6 -24
  7. data/lib/castkit/castkit.rb +61 -10
  8. data/lib/castkit/cli/generate.rb +98 -0
  9. data/lib/castkit/cli/list.rb +200 -0
  10. data/lib/castkit/cli/main.rb +43 -0
  11. data/lib/castkit/cli.rb +24 -0
  12. data/lib/castkit/configuration.rb +116 -46
  13. data/lib/castkit/contract/base.rb +168 -0
  14. data/lib/castkit/contract/data_object.rb +62 -0
  15. data/lib/castkit/contract/result.rb +74 -0
  16. data/lib/castkit/contract/validator.rb +248 -0
  17. data/lib/castkit/contract.rb +67 -0
  18. data/lib/castkit/{data_object_extensions → core}/attribute_types.rb +21 -7
  19. data/lib/castkit/{data_object_extensions → core}/attributes.rb +8 -3
  20. data/lib/castkit/core/config.rb +74 -0
  21. data/lib/castkit/core/registerable.rb +59 -0
  22. data/lib/castkit/data_object.rb +56 -67
  23. data/lib/castkit/error.rb +15 -3
  24. data/lib/castkit/ext/attribute/access.rb +67 -0
  25. data/lib/castkit/ext/attribute/error_handling.rb +63 -0
  26. data/lib/castkit/ext/attribute/options.rb +142 -0
  27. data/lib/castkit/ext/attribute/validation.rb +85 -0
  28. data/lib/castkit/ext/data_object/contract.rb +96 -0
  29. data/lib/castkit/ext/data_object/deserialization.rb +167 -0
  30. data/lib/castkit/ext/data_object/plugins.rb +86 -0
  31. data/lib/castkit/ext/data_object/serialization.rb +61 -0
  32. data/lib/castkit/inflector.rb +47 -0
  33. data/lib/castkit/plugins.rb +82 -0
  34. data/lib/castkit/serializers/base.rb +94 -0
  35. data/lib/castkit/serializers/default_serializer.rb +156 -0
  36. data/lib/castkit/types/base.rb +122 -0
  37. data/lib/castkit/types/boolean.rb +47 -0
  38. data/lib/castkit/types/collection.rb +35 -0
  39. data/lib/castkit/types/date.rb +34 -0
  40. data/lib/castkit/types/date_time.rb +34 -0
  41. data/lib/castkit/types/float.rb +46 -0
  42. data/lib/castkit/types/integer.rb +46 -0
  43. data/lib/castkit/types/string.rb +44 -0
  44. data/lib/castkit/types.rb +15 -0
  45. data/lib/castkit/validators/base.rb +59 -0
  46. data/lib/castkit/validators/boolean_validator.rb +39 -0
  47. data/lib/castkit/validators/collection_validator.rb +29 -0
  48. data/lib/castkit/validators/float_validator.rb +31 -0
  49. data/lib/castkit/validators/integer_validator.rb +31 -0
  50. data/lib/castkit/validators/numeric_validator.rb +2 -2
  51. data/lib/castkit/validators/string_validator.rb +3 -4
  52. data/lib/castkit/version.rb +1 -1
  53. data/lib/castkit.rb +2 -0
  54. data/lib/generators/base.rb +97 -0
  55. data/lib/generators/contract.rb +68 -0
  56. data/lib/generators/data_object.rb +48 -0
  57. data/lib/generators/plugin.rb +25 -0
  58. data/lib/generators/serializer.rb +28 -0
  59. data/lib/generators/templates/contract.rb.tt +24 -0
  60. data/lib/generators/templates/contract_spec.rb.tt +76 -0
  61. data/lib/generators/templates/data_object.rb.tt +15 -0
  62. data/lib/generators/templates/data_object_spec.rb.tt +36 -0
  63. data/lib/generators/templates/plugin.rb.tt +37 -0
  64. data/lib/generators/templates/plugin_spec.rb.tt +18 -0
  65. data/lib/generators/templates/serializer.rb.tt +24 -0
  66. data/lib/generators/templates/serializer_spec.rb.tt +14 -0
  67. data/lib/generators/templates/type.rb.tt +55 -0
  68. data/lib/generators/templates/type_spec.rb.tt +42 -0
  69. data/lib/generators/templates/validator.rb.tt +26 -0
  70. data/lib/generators/templates/validator_spec.rb.tt +23 -0
  71. data/lib/generators/type.rb +29 -0
  72. data/lib/generators/validator.rb +41 -0
  73. metadata +74 -15
  74. data/lib/castkit/attribute_extensions/access.rb +0 -65
  75. data/lib/castkit/attribute_extensions/casting.rb +0 -147
  76. data/lib/castkit/attribute_extensions/error_handling.rb +0 -83
  77. data/lib/castkit/attribute_extensions/options.rb +0 -131
  78. data/lib/castkit/attribute_extensions/serialization.rb +0 -89
  79. data/lib/castkit/attribute_extensions/validation.rb +0 -72
  80. data/lib/castkit/data_object_extensions/config.rb +0 -113
  81. data/lib/castkit/data_object_extensions/deserialization.rb +0 -110
  82. data/lib/castkit/default_serializer.rb +0 -123
  83. data/lib/castkit/serializer.rb +0 -92
  84. data/lib/castkit/validators.rb +0 -4
data/castkit.gemspec CHANGED
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.require_paths = ["lib"]
34
34
 
35
35
  # Runtime dependencies
36
+ spec.add_dependency "thor"
36
37
 
37
38
  # Development dependencies
38
39
  spec.add_development_dependency "rspec"
@@ -1,23 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "error"
4
- require_relative "data_object"
5
- require_relative "attribute_extensions/options"
6
- require_relative "attribute_extensions/casting"
7
- require_relative "attribute_extensions/access"
8
- require_relative "attribute_extensions/validation"
9
- require_relative "attribute_extensions/serialization"
4
+ require_relative "ext/attribute/options"
5
+ require_relative "ext/attribute/access"
6
+ require_relative "ext/attribute/validation"
10
7
 
11
8
  module Castkit
12
9
  # Represents a typed attribute on a Castkit::DataObject.
13
10
  #
14
11
  # Provides casting, validation, access control, and serialization behavior.
15
12
  class Attribute
16
- include Castkit::AttributeExtensions::Options
17
- include Castkit::AttributeExtensions::Casting
18
- include Castkit::AttributeExtensions::Access
19
- include Castkit::AttributeExtensions::Validation
20
- include Castkit::AttributeExtensions::Serialization
13
+ include Castkit::Ext::Attribute::Options
14
+ include Castkit::Ext::Attribute::Access
15
+ include Castkit::Ext::Attribute::Validation
21
16
 
22
17
  # @return [Symbol] the attribute name
23
18
  attr_reader :field
@@ -106,19 +101,6 @@ module Castkit
106
101
  end
107
102
  end
108
103
 
109
- # Validates the final value against a validator if required.
110
- #
111
- # @param value [Object]
112
- # @param context [Symbol, String]
113
- # @return [void]
114
- def validate_value!(value, context:)
115
- return if value.nil? && optional?
116
- return if type.is_a?(Array) || dataobject?
117
-
118
- validator = options[:validator] || Castkit.configuration.validator_for(type)
119
- validator&.call(value, options: options, context: context)
120
- end
121
-
122
104
  # Raises a Castkit::AttributeError with optional context.
123
105
  #
124
106
  # @param message [String]
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "configuration"
4
+ require_relative "inflector"
4
5
 
5
6
  # Castkit is a lightweight, type-safe data object system for Ruby.
6
7
  #
@@ -15,42 +16,92 @@ require_relative "configuration"
15
16
  #
16
17
  # user = UserDto.new(name: "Alice", age: 30)
17
18
  # user.to_h #=> { name: "Alice", age: 30 }
19
+ #
20
+ # @see Castkit::Contract
21
+ # @see Castkit::DataObject
18
22
  module Castkit
23
+ # Namespace used for registering generated DataObjects.
24
+ module DataObjects; end
25
+
26
+ # Namespace used for registering generated contracts.
27
+ module Contracts; end
28
+
29
+ # Namespace used for registering generated plugins.
30
+ module Plugins; end
31
+
19
32
  class << self
20
33
  # Yields the global configuration object for customization.
21
34
  #
22
- # @example
35
+ # @example Disabling array enforcement
23
36
  # Castkit.configure do |config|
24
- # config.enforce_boolean_casting = false
37
+ # config.enforce_typing = false
25
38
  # end
26
39
  #
27
- # @yieldparam config [Castkit::Configuration]
40
+ # @yieldparam config [Castkit::Configuration] the mutable config object
28
41
  # @return [void]
29
42
  def configure
30
43
  yield(configuration)
31
44
  end
32
45
 
33
- # Retrieves the global Castkit configuration.
46
+ # Retrieves the global Castkit configuration instance.
34
47
  #
35
- # @return [Castkit::Configuration] the configuration instance
48
+ # @return [Castkit::Configuration] the configuration object
36
49
  def configuration
37
50
  @configuration ||= Configuration.new
38
51
  end
39
52
 
40
- # Generates a warning message if configuration.enable_warnings == true.
53
+ # Emits a warning to STDERR if `enable_warnings` is enabled in config.
41
54
  #
42
- # @param message [String] The warning message
55
+ # @param message [String] the warning message
43
56
  # @return [void]
44
57
  def warning(message)
45
58
  warn message if configuration.enable_warnings
46
59
  end
47
60
 
48
- # Determine if an object is a subclass of Castkit::DataObject.
61
+ # Checks whether a given object is a subclass of Castkit::DataObject.
49
62
  #
50
- # @param obj [Object] The object to check
51
- # @return [Boolean]
63
+ # @param obj [Object] the object to test
64
+ # @return [Boolean] true if obj is a Castkit::DataObject class
52
65
  def dataobject?(obj)
53
66
  obj.is_a?(Class) && obj.ancestors.include?(Castkit::DataObject)
54
67
  end
68
+
69
+ # Returns a type caster lambda for the given type.
70
+ #
71
+ # Type casting performs both validation and deserialization on the provided value.
72
+ #
73
+ # @param type [Symbol] the registered type (e.g. :string)
74
+ # @return [Proc] a lambda that accepts a value and options and returns a casted result
75
+ def type_caster(type)
76
+ type_definition = configuration.fetch_type(type)
77
+
78
+ lambda do |value, validator: nil, options: {}, context: nil|
79
+ type_definition.class.cast!(value, validator: validator, options: options, context: context)
80
+ end
81
+ end
82
+
83
+ # Returns a serializer lambda for the given type.
84
+ #
85
+ # @param type [Symbol] the registered type (e.g. :string)
86
+ # @return [Proc] a lambda that calls `.serialize` on the type
87
+ def type_serializer(type)
88
+ ->(value) { configuration.fetch_type(type).serialize(value) }
89
+ end
90
+
91
+ # Returns a deserializer lambda for the given type.
92
+ #
93
+ # @param type [Symbol] the registered type (e.g. :string)
94
+ # @return [Proc] a lambda that calls `.deserialize` on the type
95
+ def type_deserializer(type)
96
+ ->(value) { configuration.fetch_type(type).deserialize(value) }
97
+ end
98
+
99
+ # Returns a validator lambda for the given type.
100
+ #
101
+ # @param type [Symbol] the registered type (e.g. :string)
102
+ # @return [Proc] a lambda that calls `.validate!` on the type
103
+ def type_validator(type)
104
+ ->(value) { configuration.fetch_type(type).validate!(value) }
105
+ end
55
106
  end
56
107
  end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require_relative "../../generators/contract"
5
+ require_relative "../../generators/data_object"
6
+ require_relative "../../generators/plugin"
7
+ require_relative "../../generators/serializer"
8
+ require_relative "../../generators/type"
9
+ require_relative "../../generators/validator"
10
+
11
+ module Castkit
12
+ module CLI
13
+ # Thor CLI class for generating Castkit components.
14
+ #
15
+ # Provides `castkit generate` commands for each major Castkit component, including types,
16
+ # data objects, contracts, validators, serializers, and plugins.
17
+ #
18
+ # All generators support the `--no-spec` flag to skip spec file creation.
19
+ class Generate < Thor
20
+ desc "contract NAME", "Generates a new Castkit contract"
21
+ method_option :spec, type: :boolean, default: true
22
+ # Generates a new contract class.
23
+ #
24
+ # @param name [String] the class name for the contract
25
+ # @param fields [Array<String>] optional attribute definitions
26
+ # @return [void]
27
+ def contract(name, *fields)
28
+ args = [Castkit::Inflector.pascalize(name), fields]
29
+ args << "--no-spec" unless options[:spec]
30
+ Castkit::Generators::Contract.start(args)
31
+ end
32
+
33
+ desc "dataobject NAME", "Generates a new Castkit DataObject"
34
+ method_option :spec, type: :boolean, default: true
35
+ # Generates a new DataObject class.
36
+ #
37
+ # @param name [String] the class name for the data object
38
+ # @param fields [Array<String>] optional attribute definitions
39
+ # @return [void]
40
+ def dataobject(name, *fields)
41
+ args = [Castkit::Inflector.pascalize(name), fields]
42
+ args << "--no-spec" unless options[:spec]
43
+ Castkit::Generators::DataObject.start(args)
44
+ end
45
+
46
+ desc "plugin NAME", "Generates a new Castkit plugin"
47
+ method_option :spec, type: :boolean, default: true
48
+ # Generates a new plugin module.
49
+ #
50
+ # @param name [String] the module name for the plugin
51
+ # @param fields [Array<String>] optional stub fields
52
+ # @return [void]
53
+ def plugin(name, *fields)
54
+ args = [Castkit::Inflector.pascalize(name), fields]
55
+ args << "--no-spec" unless options[:spec]
56
+ Castkit::Generators::Plugin.start(args)
57
+ end
58
+
59
+ desc "serializer NAME", "Generates a new Castkit serializer"
60
+ method_option :spec, type: :boolean, default: true
61
+ # Generates a new custom serializer class.
62
+ #
63
+ # @param name [String] the class name for the serializer
64
+ # @param fields [Array<String>] optional stub fields
65
+ # @return [void]
66
+ def serializer(name, *fields)
67
+ args = [Castkit::Inflector.pascalize(name), fields]
68
+ args << "--no-spec" unless options[:spec]
69
+ Castkit::Generators::Serializer.start(args)
70
+ end
71
+
72
+ desc "type NAME", "Generates a new Castkit type"
73
+ method_option :spec, type: :boolean, default: true
74
+ # Generates a new custom type.
75
+ #
76
+ # @param name [String] the class name for the type
77
+ # @return [void]
78
+ def type(name)
79
+ args = [Castkit::Inflector.pascalize(name)]
80
+ args << "--no-spec" unless options[:spec]
81
+ Castkit::Generators::Type.start(args)
82
+ end
83
+
84
+ desc "validator NAME", "Generates a new Castkit validator"
85
+ method_option :spec, type: :boolean, default: true
86
+ # Generates a new validator class.
87
+ #
88
+ # @param name [String] the class name for the validator
89
+ # @param fields [Array<String>] optional stub fields
90
+ # @return [void]
91
+ def validator(name, *fields)
92
+ args = [Castkit::Inflector.pascalize(name), fields]
93
+ args << "--no-spec" unless options[:spec]
94
+ Castkit::Generators::Validator.start(args)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require "castkit"
5
+ require_relative "../../generators/contract"
6
+ require_relative "../../generators/data_object"
7
+ require_relative "../../generators/plugin"
8
+ require_relative "../../generators/serializer"
9
+ require_relative "../../generators/type"
10
+ require_relative "../../generators/validator"
11
+
12
+ module Castkit
13
+ module CLI
14
+ # CLI commands for listing internal Castkit registry components.
15
+ #
16
+ # Supports listing:
17
+ # - Registered types (`castkit list types`)
18
+ # - Available validators (`castkit list validators`)
19
+ #
20
+ # @example Show all available types
21
+ # $ castkit list types
22
+ #
23
+ # @example Show all defined validators
24
+ # $ castkit list validators
25
+ class List < Thor
26
+ desc "types", "Lists registered Castkit types"
27
+ # Lists registered Castkit types, grouped into native and custom-defined.
28
+ #
29
+ # @return [void]
30
+ def types
31
+ all_keys = Castkit.configuration.types
32
+ default_keys = Castkit::Configuration::DEFAULT_TYPES.keys
33
+
34
+ native_types(all_keys, default_keys)
35
+ custom_types(all_keys, default_keys)
36
+ end
37
+
38
+ desc "contracts", "Lists all generated Castkit contracts"
39
+ # Lists all Castkit contract classes defined in the file system or registered under the Castkit namespace.
40
+ #
41
+ # @return [void]
42
+ def contracts
43
+ list_files("contracts")
44
+ end
45
+
46
+ desc "dataobjects", "Lists all generated Castkit DataObjects"
47
+ # Lists all Castkit DataObjects classes defined in the file system or registered under the Castkit namespace.
48
+ #
49
+ # @return [void]
50
+ def dataobjects
51
+ list_files("data_objects")
52
+ end
53
+
54
+ desc "serializers", "Lists all generated Castkit serializers"
55
+ # Lists all Castkit serializers classes defined in the file system or registered under the Castkit namespace.
56
+ #
57
+ # @return [void]
58
+ def serializers
59
+ list_files("serializers")
60
+ end
61
+
62
+ desc "validators", "Lists all generated Castkit validators"
63
+ # Lists all Castkit validator classes defined in the file system or registered under the Castkit namespace.
64
+ #
65
+ # @return [void]
66
+ def validators
67
+ list_files("validators")
68
+ end
69
+
70
+ private
71
+
72
+ # Prints all native types and their aliases.
73
+ #
74
+ # @param all_types [Hash<Symbol, Object>] all registered types
75
+ # @param default_keys [Array<Symbol>] predefined native type keys
76
+ # @return [void]
77
+ def native_types(all_types, default_keys)
78
+ alias_map = reverse_grouped(Castkit::Configuration::TYPE_ALIASES)
79
+ native = all_types.slice(*default_keys)
80
+
81
+ say "Native Types:", :green
82
+ native.each do |name, type|
83
+ aliases = alias_map[name] || []
84
+ list_type(type.class, [name, *aliases].map(&:to_sym))
85
+ end
86
+ end
87
+
88
+ # Prints all custom (non-native, non-alias) registered types.
89
+ #
90
+ # @param all_types [Hash<Symbol, Object>]
91
+ # @param default_keys [Array<Symbol>]
92
+ # @return [void]
93
+ def custom_types(all_types, default_keys)
94
+ alias_keys = Castkit::Configuration::TYPE_ALIASES.keys.map(&:to_sym)
95
+ custom = all_types.except(*default_keys).reject { |k, _| alias_keys.include?(k) }
96
+
97
+ say "\nCustom Types:", :green
98
+ return no_custom_types if custom.empty?
99
+
100
+ grouped_custom_types(custom)
101
+ end
102
+
103
+ # Outputs a fallback message if no custom types exist.
104
+ #
105
+ # @return [void]
106
+ def no_custom_types
107
+ say " No registered types, register with " \
108
+ "#{set_color("Castkit.configure { |c| c.register_type(:type, Type) }", :yellow)}"
109
+ end
110
+
111
+ # Groups and prints custom types by their class.
112
+ #
113
+ # @param types [Hash<Symbol, Object>]
114
+ # @return [void]
115
+ def grouped_custom_types(types)
116
+ types.group_by { |_, inst| inst.class }.each do |klass, group|
117
+ list_type(klass, group.map(&:first).map(&:to_sym))
118
+ end
119
+ end
120
+
121
+ # Reverses a hash of alias => type into type => [aliases].
122
+ #
123
+ # @param hash [Hash]
124
+ # @return [Hash{Symbol => Array<Symbol>}]
125
+ def reverse_grouped(hash)
126
+ hash.each_with_object(Hash.new { |h, k| h[k] = [] }) do |(k, v), acc|
127
+ acc[v] << k
128
+ end
129
+ end
130
+
131
+ # Prints a type or class with all its symbol aliases.
132
+ #
133
+ # @param klass [Class]
134
+ # @param keys [Array<Symbol>]
135
+ # @return [void]
136
+ def list_type(klass, keys)
137
+ types = keys.uniq.sort.map { |k| set_color(":#{k}", :yellow) }.join(", ")
138
+ say " #{(klass.name || "<AnonymousType>").ljust(34)} - #{types}"
139
+ end
140
+
141
+ # Lists class references for a component (e.g. validators), distinguishing by source (file or custom).
142
+ #
143
+ # @param component [String] base namespace (e.g. "validators")
144
+ # @return [void]
145
+ def list_files(component)
146
+ path = "lib/castkit/#{component}"
147
+ all_classes, file_classes = component_classes(component, path)
148
+ return say "No registered #{Castkit::Inflector.pascalize(component)} found." if all_classes.empty?
149
+
150
+ max_width = all_classes.map(&:length).max + 5
151
+ say "Castkit #{Castkit::Inflector.pascalize(component)}", :green
152
+
153
+ all_classes.each do |klass|
154
+ tag = file_classes.include?(klass) ? set_color("[Castkit]", :yellow) : set_color("[Custom]", :green)
155
+ say " #{klass.ljust(max_width)} #{tag}"
156
+ end
157
+ end
158
+
159
+ # Gathers all registered and defined constants for a component.
160
+ #
161
+ # @param component [String]
162
+ # @param path [String]
163
+ # @return [Array<[Array<String>, Set<String>]>]
164
+ def component_classes(component, path)
165
+ namespace = Castkit.const_get(Castkit::Inflector.pascalize(component))
166
+ file_classes = file_classes(namespace, path)
167
+ defined_classes = defined_classes(namespace)
168
+
169
+ all_classes = (file_classes + defined_classes).to_a.sort
170
+ [all_classes, file_classes]
171
+ end
172
+
173
+ # Converts file names into class names for a given component.
174
+ #
175
+ # @param namespace [Module]
176
+ # @param path [String]
177
+ # @return [Set<String>]
178
+ def file_classes(namespace, path)
179
+ classes = Dir.glob("#{path}/*.rb")
180
+ .map { |f| File.basename(f, ".rb") }
181
+ .reject { |f| f.to_s == "base" }
182
+ .map { |base| "#{namespace}::#{Castkit::Inflector.pascalize(base)}" }
183
+
184
+ classes.to_set
185
+ end
186
+
187
+ # Lists actual constants under a namespace, filtering out missing definitions.
188
+ #
189
+ # @param namespace [Module]
190
+ # @return [Set<String>]
191
+ def defined_classes(namespace)
192
+ namespace.constants
193
+ .reject { |const| const.to_s == "Base" }
194
+ .map { |const| "#{namespace}::#{const}" }
195
+ .select { |klass| Object.const_defined?(klass) }
196
+ .to_set
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "generate"
4
+ require_relative "list"
5
+
6
+ module Castkit
7
+ module CLI
8
+ # Main CLI entry point for Castkit.
9
+ #
10
+ # Provides top-level commands for printing the gem version and generating Castkit components.
11
+ #
12
+ # @example Print the version
13
+ # $ castkit version
14
+ #
15
+ # @example Generate a DataObject
16
+ # $ castkit generate dataobject User name:string age:integer
17
+ class Main < Thor
18
+ desc "version", "Prints the version"
19
+ # Outputs the current Castkit version.
20
+ #
21
+ # @return [void]
22
+ def version
23
+ puts Castkit::VERSION
24
+ end
25
+
26
+ desc "generate TYPE NAME", "Generate a Castkit component"
27
+ # Dispatches to the `castkit generate` subcommands.
28
+ #
29
+ # Supports generating components like `type`, `dataobject`, `contract`, etc.
30
+ #
31
+ # @return [void]
32
+ subcommand "generate", Castkit::CLI::Generate
33
+
34
+ desc "list COMPONENT", "List registered Castkit components"
35
+ # Dispatches to the `castkit list` subcommands.
36
+ #
37
+ # Supports listing components like `type`, `dataobject`, `contract`, etc.
38
+ #
39
+ # @return [void]
40
+ subcommand "list", Castkit::CLI::List
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require_relative "cli/main"
5
+
6
+ module Castkit
7
+ # Entrypoint for Castkit’s command-line interface.
8
+ #
9
+ # Delegates to the `Castkit::CLI::Main` Thor class, which defines all CLI commands.
10
+ #
11
+ # @example Executing from a binstub
12
+ # Castkit::CLI.start(ARGV)
13
+ #
14
+ module CLI
15
+ # Starts the Castkit CLI.
16
+ #
17
+ # @param args [Array<String>] the command-line arguments
18
+ # @param kwargs [Hash] additional keyword arguments passed to Thor
19
+ # @return [void]
20
+ def self.start(*args, **kwargs)
21
+ Castkit::CLI::Main.start(*args, **kwargs)
22
+ end
23
+ end
24
+ end