structure 3.1.0 → 3.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af5b8b6dc3dacef6201847123b04742310441ded70ec7952b42d07a668d83f2f
4
- data.tar.gz: '00385227416285e5a4d1f2cfcf2cc0e5cb94bb368cf8995b014a7bf3fd91d9c6'
3
+ metadata.gz: 91e04b84b8e6a19728bf6212bdfd08895187bbe59ebf56b47288697962ed31b2
4
+ data.tar.gz: '028e8df792d344faa2850f82504d223a6691c195203c51acd53581ee9e97064c'
5
5
  SHA512:
6
- metadata.gz: ba80d09a4867a1497133026cc4d4654e03586f677d44d07a7f2387b40fce16e8fc188bc46cc8c768663ded6387b580d3dc210ae884d14530bf62e7e56ec4ace4
7
- data.tar.gz: 8a0c8e7d5f9585a946817cc31a3cd831ea0332833030798d178ce81ee1737809226321ac105f106559358aa4ae24753368d808007ef6ab37230b6d6fc98ffe69
6
+ metadata.gz: 4e6fbbd3104fc0ed9001d66395606ab436a907cf3b1ab09f692c458b99e999e648e7b558dd0b2e8e4fb298d2c1c25decf51bef0ad5889bc9ff14f6d821c62ede
7
+ data.tar.gz: 74752c31b2898fea6c7d5c94e568f7fa9ca2724e116aa62e9d9c30f0da77d3f6f7de7b73540a8837834536bc2aa9b87f9d5b596ddd0bfd2089222e3fbec07334
@@ -13,6 +13,25 @@ module Structure
13
13
  @defaults = {}
14
14
  end
15
15
 
16
+ # DSL method for defining attributes with optional type coercion
17
+ #
18
+ # @param name [Symbol] The attribute name
19
+ # @param type [Class, Symbol, Array, nil] Type for coercion (e.g., String, :boolean, [String])
20
+ # @param from [String, nil] Source key in the data hash (defaults to name.to_s)
21
+ # @param default [Object, nil] Default value if attribute is missing
22
+ # @yield [value] Block for custom transformation
23
+ # @raise [ArgumentError] If both type and block are provided
24
+ #
25
+ # @example With type coercion
26
+ # attribute :age, Integer
27
+ #
28
+ # @example With custom source key
29
+ # attribute :created_at, Time, from: "CreatedAt"
30
+ #
31
+ # @example With transformation block
32
+ # attribute :price do |value|
33
+ # Money.new(value["amount"], value["currency"])
34
+ # end
16
35
  def attribute(name, type = nil, from: nil, default: nil, &block)
17
36
  # Always store in mappings - use attribute name as default source
18
37
  @mappings[name] = from || name.to_s
@@ -27,23 +46,30 @@ module Structure
27
46
  end
28
47
  end
29
48
 
30
- # Deduced from mappings - maintains order of definition
49
+ # Defines a callback to run after parsing
50
+ #
51
+ # @yield [instance] Block that receives the parsed instance
52
+ # @return [void]
53
+ #
54
+ # @example Validation
55
+ # after_parse do |order|
56
+ # raise "Invalid order" if order.total < 0
57
+ # end
58
+ def after_parse(&block)
59
+ @after_parse_callback = block
60
+ end
61
+
31
62
  def attributes
32
63
  @mappings.keys
33
64
  end
34
65
 
35
- # Deduced from types that are boolean
36
66
  def predicate_methods
37
67
  @types.filter_map do |name, type_lambda|
38
- if type_lambda == Types.boolean
68
+ if type_lambda == Types.boolean && !name.to_s.end_with?("?")
39
69
  predicate_name = "#{name}?"
40
70
  [predicate_name.to_sym, name]
41
71
  end
42
72
  end.to_h
43
73
  end
44
-
45
- def after_parse(&block)
46
- @after_parse_callback = block
47
- end
48
74
  end
49
75
  end
@@ -10,29 +10,26 @@ module Structure
10
10
  BOOLEAN_TRUTHY = [true, 1, "1", "t", "T", "true", "TRUE", "on", "ON"].freeze
11
11
  private_constant :BOOLEAN_TRUTHY
12
12
 
13
- # Boolean conversion
14
- # Memoized so predicate method detection works via object identity comparison
15
13
  def boolean
16
14
  @boolean ||= ->(val) { BOOLEAN_TRUTHY.include?(val) }
17
15
  end
18
16
 
19
- # Generic handler for classes with kernel methods (String, Integer, Float, etc.)
20
- def kernel(type)
21
- ->(val) { Kernel.send(type.name, val) }
22
- end
23
-
24
- # Handler for classes with parse methods (e.g., Date, Time, URI, nested Structure classes)
25
- def parseable(type)
26
- ->(val) { type.parse(val) }
27
- end
28
-
29
- # Create coercer for array elements
30
- def array(element_type)
31
- element_coercer = coerce(element_type)
32
- ->(array) { array.map { |element| element_coercer.call(element) } }
33
- end
34
-
35
17
  # Main factory method for creating type coercers
18
+ #
19
+ # @param type [Class, Symbol, Array] Type specification
20
+ # @return [Proc, Object] Coercion proc or the type itself if no coercion available
21
+ #
22
+ # @example Boolean type
23
+ # coerce(:boolean) # => boolean proc
24
+ #
25
+ # @example Kernel types
26
+ # coerce(Integer) # => proc that calls Kernel.Integer
27
+ #
28
+ # @example Parseable types
29
+ # coerce(Date) # => proc that calls Date.parse
30
+ #
31
+ # @example Array types
32
+ # coerce([String]) # => proc that coerces array elements to String
36
33
  def coerce(type)
37
34
  case type
38
35
  when :boolean
@@ -55,5 +52,20 @@ module Structure
55
52
  type
56
53
  end
57
54
  end
55
+
56
+ private
57
+
58
+ def kernel(type)
59
+ ->(val) { Kernel.send(type.name, val) }
60
+ end
61
+
62
+ def parseable(type)
63
+ ->(val) { type.parse(val) }
64
+ end
65
+
66
+ def array(element_type)
67
+ element_coercer = coerce(element_type)
68
+ ->(array) { array.map { |element| element_coercer.call(element) } }
69
+ end
58
70
  end
59
71
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Structure
4
- VERSION = "3.1.0"
4
+ VERSION = "3.1.1"
5
5
  end
data/lib/structure.rb CHANGED
@@ -5,6 +5,20 @@ require "structure/builder"
5
5
  # A library for parsing data into immutable Ruby Data objects with type coercion
6
6
  module Structure
7
7
  class << self
8
+ # Creates a new Data class with attribute definitions and type coercion
9
+ #
10
+ # @yield [Builder] Block for defining attributes using the DSL
11
+ # @return [Class] A Data class with a parse method
12
+ #
13
+ # @example Basic usage
14
+ # Person = Structure.new do
15
+ # attribute :name, String
16
+ # attribute :age, Integer
17
+ # end
18
+ #
19
+ # person = Person.parse(name: "Alice", age: "30")
20
+ # person.name # => "Alice"
21
+ # person.age # => 30
8
22
  def new(&block)
9
23
  builder = Builder.new
10
24
  builder.instance_eval(&block) if block
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: structure
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hakan Ensari