philosophal 1.1.0 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d09ac65f9fd7fa000c82fa1d9e77c85e22866d2a9a1ffdfa1a63e19b36cb909b
4
- data.tar.gz: bdf93344392beabea229e214b1403e88749fd51839e68c9e675fb9566fad5e52
3
+ metadata.gz: 1df7f3c754eeef6776d0e3a18bcfdb81124e413187beb2f580dd550cbdcd046e
4
+ data.tar.gz: 03ed60c26e12f8225145e6f00a138da84e3d1aa11ffd1ab1be878df0032e6896
5
5
  SHA512:
6
- metadata.gz: f729b3f0a820e25d39e9de2eecd47cc7cd7bc12fa32cdc6306c81b02418f98507a3d814582f638822834dc3f9cae055b00db909a3cc66c3112c7ccb8118aaf90
7
- data.tar.gz: a1ab12ea326c278c6d7eab6b555605642f0ce34d30d27782efe4a6991cbd3fc3b63917cbef00a8b21133b47e096056b2ba34234b40017239d556880960fa67f0
6
+ metadata.gz: ab3fd3bf30dbaba5d2936979b832b2f9a715b7dbab19eba5d08c7feb4e84aa5affd41247b294ffc7ff9a4c054dcaba932ba2cb98d9c8699b5825d1dbad4c0a9b
7
+ data.tar.gz: 2b372e50b9bcf123531cdc0df806061893e86a3ddc70eddc2cc47731a017cff18dea606aea8c3477c2d8f2adf1faaa051c3728ad8645b166a0c5c120e583f951
data/.rubocop.yml CHANGED
@@ -6,4 +6,7 @@ require:
6
6
 
7
7
  AllCops:
8
8
  TargetRubyVersion: 3.1
9
- NewCops: enable
9
+ NewCops: enable
10
+
11
+ Style/Documentation:
12
+ Enabled: false
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.2.0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Philosophal
4
+ module Loaders
5
+ class LoadError < StandardError; end
6
+ end
7
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Philosophal
4
+ module Loaders
5
+ class JsonLoader
6
+ def initialize(klass)
7
+ @klass = klass
8
+ end
9
+
10
+ def load(json)
11
+ return load_from_hash(json) if json.is_a?(Hash)
12
+ return load_from_array(json) if json.is_a?(Array)
13
+
14
+ raise LoadError, 'invalid json parameter' unless json.is_a?(String)
15
+
16
+ first_char = json[0]
17
+
18
+ return load_from_json(json) if first_char == '{'
19
+
20
+ return load_from_json_collection(json) if first_char == '['
21
+
22
+ load_from_path(json)
23
+ end
24
+
25
+ private
26
+
27
+ def load_from_array(array)
28
+ raise LoadError, 'invalid json parameter' if array.find { |hash| !hash.is_a?(Hash) }
29
+
30
+ array.map! do |hash|
31
+ load_from_hash(hash)
32
+ end
33
+ end
34
+
35
+ def load_from_hash(hash)
36
+ obj = @klass.new
37
+
38
+ hash.each_key do |key|
39
+ setter = setter_from_key(key)
40
+ next unless obj.respond_to?(setter)
41
+
42
+ obj.public_send(setter, hash.delete(key))
43
+ end
44
+
45
+ obj
46
+ end
47
+
48
+ def setter_from_key(key)
49
+ real_key = @klass.philosophal_properties.json_names_h[key]
50
+ property = @klass.philosophal_properties[real_key]
51
+
52
+ return :"#{property.name}=" if property
53
+
54
+ :"#{key}="
55
+ end
56
+
57
+ def load_from_json(str)
58
+ hash = JSON.parse(str, symbolize_names: true)
59
+ load_from_hash(hash)
60
+ end
61
+
62
+ def load_from_json_collection(json)
63
+ array = JSON.parse(json, symbolize_names: true)
64
+ load_from_array(array)
65
+ end
66
+
67
+ def load_from_path(path)
68
+ raise LoadError, "no such file #{path}" unless File.exist?(path)
69
+
70
+ str = File.read(path)
71
+ load_from_json(str)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Philosophal
4
+ module Loaders
5
+ autoload :JsonLoader, 'philosophal/loaders/json_loader'
6
+ autoload :LoadError, 'philosophal/loaders/errors'
7
+ end
8
+ end
@@ -29,11 +29,23 @@ module Philosophal
29
29
  end
30
30
 
31
31
  def immutables
32
- @properties_index.select { |_, v| v.immutable }
32
+ return @immutables if defined?(@immutables)
33
+
34
+ @immutables = @properties_index.select { |_, v| v.immutable }
33
35
  end
34
36
 
35
37
  def mutables
36
- @properties_index.reject { |_, v| v.immutable }
38
+ return @mutables if defined?(@mutables)
39
+
40
+ @mutables = @properties_index.reject { |_, v| v.immutable }
41
+ end
42
+
43
+ def json_names_h
44
+ return @json_names_h if defined?(@json_names_h)
45
+
46
+ @json_names_h = @properties_index.to_h do |key, property|
47
+ [property.json_name, key]
48
+ end
37
49
  end
38
50
  end
39
51
  end
@@ -3,10 +3,11 @@
3
3
  module Philosophal
4
4
  module Properties
5
5
  autoload :Schema, 'philosophal/properties/schema'
6
+ autoload :JSONLoader, 'philosophal/loaders/json_loader'
6
7
 
7
8
  include Philosophal::Types
8
9
 
9
- def cprop(name, type, default: nil, transform: nil, immutable: false, description: nil)
10
+ def cprop(name, type, default: nil, transform: nil, immutable: false, description: nil, json: false)
10
11
  default.freeze if default && !(default.is_a?(Proc) || default.frozen?)
11
12
 
12
13
  if transform && !(transform.is_a?(Proc) || transform.is_a?(Symbol))
@@ -23,7 +24,15 @@ module Philosophal
23
24
  description.freeze unless description.frozen?
24
25
  end
25
26
 
26
- property = __philosophal_property_class__.new(name:, type:, default:, transform:, immutable:, description:)
27
+ if json
28
+ unless json.is_a?(TrueClass) || json.is_a?(String) || json.is_a?(Symbol)
29
+ raise Philosophal::ArgumentError, 'json param must be true or a String or a Symbol.'
30
+ end
31
+
32
+ json = json.to_sym if json.is_a?(String)
33
+ end
34
+
35
+ property = __philosophal_property_class__.new(name:, type:, default:, transform:, immutable:, description:, json:)
27
36
 
28
37
  philosophal_properties << property
29
38
  __define_philosophal_methods__(property)
@@ -43,7 +52,9 @@ module Philosophal
43
52
  def philosophal_descriptions
44
53
  return @philosophal_descriptions if defined?(@philosophal_descriptions)
45
54
 
46
- @philosophal_descriptions = philosophal_properties.properties_index.values.select(&:description).to_h do |property|
55
+ @philosophal_descriptions = philosophal_properties.properties_index.values
56
+ .select(&:description)
57
+ .to_h do |property|
47
58
  [
48
59
  property.name,
49
60
  property.description
@@ -52,6 +63,12 @@ module Philosophal
52
63
  end
53
64
  alias cprop_descriptions philosophal_descriptions
54
65
 
66
+ def json
67
+ return @json if defined?(@json)
68
+
69
+ @json = Philosophal::Loaders::JsonLoader.new(self)
70
+ end
71
+
55
72
  private
56
73
 
57
74
  def __philosophal_property_class__
@@ -86,12 +103,12 @@ module Philosophal
86
103
  end
87
104
 
88
105
  keys_str = keys_map.map { |k, v| [k, v.inspect].join(': ') }.join(', ')
89
- "#{self.class}:#{format('0x00%x', (object_id << 1))} #{keys_str}"
106
+ "#{self.class}:#{format('0x00%x', object_id << 1)} #{keys_str}"
90
107
  end
91
108
  alias cprop_inspect philosophal_inspect
92
109
 
93
110
  def philosophal_inspect_map
94
- self.class.philosophal_properties.properties_index.values.to_h do |property|
111
+ philosophal_values.to_h do |property|
95
112
  [
96
113
  property.name,
97
114
  send(property.name)
@@ -99,6 +116,23 @@ module Philosophal
99
116
  end
100
117
  end
101
118
  alias cprop_inspect_map philosophal_inspect_map
119
+
120
+ def philosophal_values
121
+ self.class.philosophal_properties.properties_index.values
122
+ end
123
+
124
+ def to_json_hash
125
+ philosophal_values.select(&:json).to_h do |property|
126
+ [
127
+ property.json_name,
128
+ send(property.name)
129
+ ]
130
+ end
131
+ end
132
+
133
+ def to_json(*_args)
134
+ to_json_hash.to_json
135
+ end
102
136
  end
103
137
  end
104
138
  end
@@ -2,16 +2,23 @@
2
2
 
3
3
  module Philosophal
4
4
  class Property
5
- def initialize(name:, type:, default:, transform:, immutable:, description:)
5
+ def initialize(name:, type:, default:, transform:, immutable:, description:, json:)
6
6
  @name = name
7
7
  @type = type
8
8
  @default = default
9
9
  @transform = transform
10
10
  @immutable = immutable
11
11
  @description = description
12
+ @json = json
12
13
  end
13
14
 
14
- attr_reader :name, :type, :default, :transform, :immutable, :description
15
+ attr_reader :name, :type, :default, :transform, :immutable, :description, :json
16
+
17
+ def json_name
18
+ return @json if @json.is_a?(Symbol)
19
+
20
+ @name
21
+ end
15
22
 
16
23
  def default?
17
24
  @default != nil
@@ -82,7 +89,7 @@ module Philosophal
82
89
  @name.name <<
83
90
  "_description\n " \
84
91
  '%(' << @description << ')' \
85
- "\nend\n"
92
+ "\nend\n"
86
93
  end
87
94
  end
88
95
  end
data/lib/philosophal.rb CHANGED
@@ -4,6 +4,7 @@ require 'date'
4
4
  require 'pathname'
5
5
  require 'set'
6
6
  require 'time'
7
+ require 'json'
7
8
 
8
9
  module Philosophal
9
10
  autoload :Convertor, 'philosophal/convertor'
@@ -13,6 +14,7 @@ module Philosophal
13
14
  autoload :Property, 'philosophal/property'
14
15
 
15
16
  autoload :Types, 'philosophal/types'
17
+ autoload :Loaders, 'philosophal/loaders'
16
18
 
17
19
  autoload :TypeError, 'philosophal/errors/type_error'
18
20
  autoload :ArgumentError, 'philosophal/errors/argument_error'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philosophal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxime Désécot
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-26 00:00:00.000000000 Z
11
+ date: 2026-06-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Auto convert value on setter method call
14
14
  email:
@@ -29,6 +29,9 @@ files:
29
29
  - lib/philosophal/convertor.rb
30
30
  - lib/philosophal/errors/argument_error.rb
31
31
  - lib/philosophal/errors/type_error.rb
32
+ - lib/philosophal/loaders.rb
33
+ - lib/philosophal/loaders/errors.rb
34
+ - lib/philosophal/loaders/json_loader.rb
32
35
  - lib/philosophal/properties.rb
33
36
  - lib/philosophal/properties/schema.rb
34
37
  - lib/philosophal/property.rb