easy_talk 0.1.10 → 0.2.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: 1ebe87803e47220d1a3f6396a1735fd2aa04b3f2b1428bea43cd873cb32f3bca
4
- data.tar.gz: ecdaaa2801742335160a89a38a92ef9b402be563d3ce0e54c52f3068d75c93ce
3
+ metadata.gz: d3b84eeed5e8d6430c3bbaf97936ec90a29554dcbd71905553ecaf2f66b82877
4
+ data.tar.gz: 74fa329ca8574c8d8d8ec2b3daf6dee3a8d46a3550c53fb30ceb1709487243d9
5
5
  SHA512:
6
- metadata.gz: 866e44d124957d2149bd67584c0e35129bd922c98da0bb9d4b37cead66636d84b508290be35b4ce79ad3940bd556585ee604aeb79c220f898450624765e3fd50
7
- data.tar.gz: 551cd5c6f3de517efd56fadb407fd723de14764d3520b7be7ee73e12a7027d391816452ad13a00752e0fa690d5da2eef4aff2d0b12b585ed686eeb31635875ac
6
+ metadata.gz: 59be99a0311ec3c5d941e63cc2299e26d2a84c1a53ff88f6bd561dbd1b046dc3f4e5d68c8037724cd295df8d542a7a24621374cc535422920200a11ae66507e5
7
+ data.tar.gz: 2eabc32e703f00a68d47d1152fc1a42cc963e0f5ba05aea76b57b7ccccde670dcb4361811b8af812b85d2c78880f7b375e536d7ce7f0f12a7177dd8b80046775
data/.rubocop.yml CHANGED
@@ -27,4 +27,7 @@ Layout/LineLength:
27
27
 
28
28
  RSpec/DescribeClass:
29
29
  Exclude:
30
- - 'spec/easy_talk/examples/**/*'
30
+ - 'spec/easy_talk/examples/**/*'
31
+
32
+ RSpec/MultipleExpectations:
33
+ Max: 4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.2.1] - 2024-05-06
2
+ - Run JSON Schema validations using ActiveModel's validations.
3
+
4
+ ## [0.2.0] - 2024-05-01
5
+ - Added ActiveModel::API functionality to EasyTalk::Model module. That means you get all the benefits of ActiveModel::API including attribute assignment, introspections, validations, translation (i18n) and more. See https://api.rubyonrails.org/classes/ActiveModel/API.html for more information.
6
+
1
7
  ## [0.1.10] - 2024-04-29
2
8
  - Accept `:optional` key as constraint which excludes property from required node.
3
9
  - Spec fixes
data/README.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # EasyTalk
2
2
 
3
- EasyTalk is a Ruby library for defining and generating JSON Schema.
3
+ EasyTalk is a Ruby library that simplifies defining and generating JSON Schema documents, and validates that JSON data conforms to these schemas.
4
+
5
+ Key Features
6
+ * Intuitive Schema Definition: Use Ruby classes and methods to define JSON Schema documents easily.
7
+ * JSON Schema Compliance: Implements the JSON Schema specification to ensure compatibility and standards adherence.
8
+ * LLM Function Support: Ideal for integrating with Large Language Models (LLMs) such as OpenAI's GPT-3.5-turbo and GPT-4. EasyTalk enables you to effortlessly create JSON Schema documents needed to describe the inputs and outputs of LLM function calls.
9
+ * Validation: Validates JSON inputs and outputs against defined schemas to ensure they meet expected formats and types. Write custom validations using ActiveModel's validations.
10
+ * Integration with ActiveModel: EasyTalk integrates with ActiveModel to provide additional functionality such as attribute assignment, introspections, validations, translation (i18n), and more.
11
+
12
+ Inspiration
13
+ Inspired by Python's Pydantic library, EasyTalk brings similar functionality to the Ruby ecosystem, providing a Ruby-friendly approach to JSON Schema operations.
4
14
 
5
15
  Example Use:
6
16
 
@@ -41,6 +41,7 @@ module EasyTalk
41
41
  end
42
42
  end
43
43
 
44
+ # rubocop:disable Style/DoubleNegation
44
45
  def add_required_property(property_name, options)
45
46
  return if options.is_a?(Hash) && !!(options[:type].respond_to?(:nilable?) && options[:type].nilable?)
46
47
 
@@ -48,6 +49,7 @@ module EasyTalk
48
49
 
49
50
  @required_properties << property_name
50
51
  end
52
+ # rubocop:enable Style/DoubleNegation
51
53
 
52
54
  def build_property(property_name, options)
53
55
  if options.is_a?(EasyTalk::SchemaDefinition)
@@ -6,66 +6,56 @@ require 'active_support/core_ext'
6
6
  require 'active_support/time'
7
7
  require 'active_support/concern'
8
8
  require 'active_support/json'
9
- require 'json-schema'
9
+ require 'active_model'
10
+ require 'json_schemer'
11
+ require_relative 'schema_errors_mapper'
10
12
  require_relative 'builders/object_builder'
11
13
  require_relative 'schema_definition'
12
14
 
13
15
  module EasyTalk
14
- # The Model module can be included in a class to add JSON schema definition and generation support.
16
+ # The `Model` module is a mixin that provides functionality for defining and accessing the schema of a model.
17
+ #
18
+ # It includes methods for defining the schema, retrieving the schema definition,
19
+ # and generating the JSON schema for the model.
20
+ #
21
+ # Example usage:
22
+ #
23
+ # class Person
24
+ # include EasyTalk::Model
25
+ #
26
+ # define_schema do
27
+ # property :name, String, description: 'The person\'s name'
28
+ # property :age, Integer, description: 'The person\'s age'
29
+ # end
30
+ # end
31
+ #
32
+ # Person.json_schema #=> returns the JSON schema for Person
33
+ # jim = Person.new(name: 'Jim', age: 30)
34
+ # jim.valid? #=> returns true
35
+ #
36
+ # @see SchemaDefinition
15
37
  module Model
16
- # The `Model` module is a mixin that provides functionality for defining and accessing the schema of a model.
17
- #
18
- # It includes methods for defining the schema, retrieving the schema definition,
19
- # and generating the JSON schema for the model.
20
- #
21
- # Example usage:
22
- #
23
- # class MyModel
24
- # extend ClassMethods
25
- #
26
- # define_schema do
27
- # # schema definition goes here
28
- # end
29
- # end
30
- #
31
- # MyModel.json_schema #=> returns the JSON schema for MyModel
32
- #
33
- # MyModel.schema_definition #=> returns the unvalidated schema definition for MyModel
34
- #
35
- # MyModel.ref_template #=> returns the reference template for MyModel
36
- #
37
- # MyModel.inherits_schema? #=> returns false
38
- #
39
- # MyModel.schema #=> returns the validated schema for MyModel
40
- #
41
- # MyModel.schema_definition #=> returns the unvalidated schema definition for MyModel
42
- #
43
- # MyModel.json_schema #=> returns the JSON schema for MyModel
44
- #
45
- # @see SchemaDefinition
46
- #
47
38
  def self.included(base)
39
+ base.include ActiveModel::API # Include ActiveModel::API in the class including EasyTalk::Model
40
+ base.include ActiveModel::Validations
41
+ base.extend ActiveModel::Callbacks
42
+ base.validates_with SchemaValidator
48
43
  base.extend(ClassMethods)
49
44
  end
50
45
 
51
- # Initializes a new instance of the Model class.
52
- #
53
- # @param properties [Hash] The properties to set for the instance.
54
- def initialize(properties = {})
55
- properties.each do |key, value|
56
- instance_variable_set("@#{key}", value)
57
- self.class.class_eval { attr_reader key }
46
+ class SchemaValidator < ActiveModel::Validator
47
+ def validate(record)
48
+ result = schema_validation(record)
49
+ result.errors.each do |key, error_msg|
50
+ record.errors.add key.to_sym, error_msg
51
+ end
58
52
  end
59
- end
60
53
 
61
- # Checks if the model is valid.
62
- #
63
- # This method calls the `validate_json` class method on the current class,
64
- # passing the `properties` as the argument.
65
- #
66
- # @return [Boolean] true if the model is valid, false otherwise.
67
- def valid?
68
- self.class.validate_json(properties)
54
+ def schema_validation(record)
55
+ schema = JSONSchemer.schema(record.class.json_schema)
56
+ errors = schema.validate(record.properties)
57
+ SchemaErrorsMapper.new(errors)
58
+ end
69
59
  end
70
60
 
71
61
  # Returns the properties of the model as a hash with symbolized keys.
@@ -103,12 +93,12 @@ module EasyTalk
103
93
  name.humanize.titleize
104
94
  end
105
95
 
106
- # Validates the given JSON against the model's JSON schema.
107
- #
108
- # @param json [Hash] The JSON to validate.
109
- # @return [Boolean] `true` if the JSON is valid, `false` otherwise.
110
- def validate_json(json)
111
- JSON::Validator.validate(json_schema, json)
96
+ def properties
97
+ @properties ||= begin
98
+ return unless schema[:properties].present?
99
+
100
+ schema[:properties].keys.map(&:to_sym)
101
+ end
112
102
  end
113
103
 
114
104
  # Returns the JSON schema for the model.
@@ -127,6 +117,9 @@ module EasyTalk
127
117
 
128
118
  @schema_definition = SchemaDefinition.new(name)
129
119
  @schema_definition.instance_eval(&block)
120
+ attr_accessor(*properties)
121
+
122
+ @schema_defintion
130
123
  end
131
124
 
132
125
  # Returns the unvalidated schema definition for the model.
@@ -0,0 +1,21 @@
1
+ module EasyTalk
2
+ class SchemaErrorsMapper
3
+ def initialize(errors)
4
+ @errors = errors.to_a
5
+ end
6
+
7
+ def errors
8
+ @errors.each_with_object({}) do |error, hash|
9
+ if error['data_pointer'].present?
10
+ key = error['data_pointer'].split('/').compact_blank.join('.')
11
+ hash[key] = error['error']
12
+ else
13
+ error['details']['missing_keys'].each do |missing_key|
14
+ message = "#{error['error'].split(':').first}: #{missing_key}"
15
+ hash[missing_key] = message
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EasyTalk
4
- VERSION = '0.1.10'
4
+ VERSION = '0.2.1'
5
5
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_talk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergio Bayona
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-30 00:00:00.000000000 Z
11
+ date: 2024-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
14
+ name: activemodel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
@@ -25,19 +25,33 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '7.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: json-schema
28
+ name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '4'
33
+ version: '7.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '4'
40
+ version: '7.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json_schemer
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: sorbet-runtime
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -199,6 +213,7 @@ files:
199
213
  - lib/easy_talk/model.rb
200
214
  - lib/easy_talk/property.rb
201
215
  - lib/easy_talk/schema_definition.rb
216
+ - lib/easy_talk/schema_errors_mapper.rb
202
217
  - lib/easy_talk/sorbet_extension.rb
203
218
  - lib/easy_talk/tools/function_builder.rb
204
219
  - lib/easy_talk/types/all_of.rb