json_schema_view 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +58 -0
  4. data/.yardopts +1 -0
  5. data/CHANGELOG.md +5 -0
  6. data/CODE_OF_CONDUCT.md +84 -0
  7. data/Gemfile +18 -0
  8. data/LICENSE.md +202 -0
  9. data/README.md +117 -0
  10. data/Rakefile +12 -0
  11. data/json_schema_view.gemspec +42 -0
  12. data/lib/json_schema_view/base_component.rb +82 -0
  13. data/lib/json_schema_view/base_props.rb +32 -0
  14. data/lib/json_schema_view/configuration/schema_set_dictionary.rb +51 -0
  15. data/lib/json_schema_view/configuration.rb +44 -0
  16. data/lib/json_schema_view/json_schema_definable.rb +22 -0
  17. data/lib/json_schema_view/json_world_extensions/additional_properties.rb +58 -0
  18. data/lib/json_schema_view/json_world_extensions/any_of.rb +41 -0
  19. data/lib/json_schema_view/json_world_extensions/camelizable.rb +36 -0
  20. data/lib/json_schema_view/json_world_extensions/compact_optional_properties.rb +20 -0
  21. data/lib/json_schema_view/json_world_extensions/constant_property.rb +39 -0
  22. data/lib/json_schema_view/json_world_extensions/declarable.rb +55 -0
  23. data/lib/json_schema_view/json_world_extensions/enum_type.rb +45 -0
  24. data/lib/json_schema_view/json_world_extensions/map_type.rb +47 -0
  25. data/lib/json_schema_view/json_world_extensions/validatable.rb +17 -0
  26. data/lib/json_schema_view/json_world_extensions.rb +31 -0
  27. data/lib/json_schema_view/rails/generators/install/USAGE +5 -0
  28. data/lib/json_schema_view/rails/generators/install/install_generator.rb +50 -0
  29. data/lib/json_schema_view/rails/generators/install/templates/base_component.rb.tt +17 -0
  30. data/lib/json_schema_view/rails/generators/install/templates/base_props.rb.tt +7 -0
  31. data/lib/json_schema_view/rails/generators/install/templates/component_schema_set.rb.tt +25 -0
  32. data/lib/json_schema_view/rails/generators/install/templates/example/todo_item_resource.rb +52 -0
  33. data/lib/json_schema_view/rails/generators/install/templates/example/todo_list_component.rb +67 -0
  34. data/lib/json_schema_view/rails/generators/install/templates/initializer.rb.tt +15 -0
  35. data/lib/json_schema_view/rails/generators.rb +8 -0
  36. data/lib/json_schema_view/rails/rails_engine.rb +20 -0
  37. data/lib/json_schema_view/rails/tasks/json_schema_component.rake +9 -0
  38. data/lib/json_schema_view/rails.rb +8 -0
  39. data/lib/json_schema_view/renderers/base.rb +27 -0
  40. data/lib/json_schema_view/renderers/json.rb +28 -0
  41. data/lib/json_schema_view/renderers/react_on_rails.rb +17 -0
  42. data/lib/json_schema_view/renderers.rb +22 -0
  43. data/lib/json_schema_view/schema_set/constant_search_helper.rb +114 -0
  44. data/lib/json_schema_view/schema_set.rb +58 -0
  45. data/lib/json_schema_view/version.rb +5 -0
  46. data/lib/json_schema_view.rb +29 -0
  47. data/sig/json_schema_view.rbs +4 -0
  48. metadata +134 -0
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module JsonSchemaView
6
+ class Configuration
7
+ # :nodoc:
8
+ class SchemaSetDictionary < Delegator
9
+ attr_reader :hash
10
+
11
+ # @param contents [Hash, nil]
12
+ def initialize(contents = nil)
13
+ @hash = ActiveSupport::HashWithIndifferentAccess.new(contents)
14
+ super
15
+ end
16
+
17
+ # @overload {Delegator#__getobj__}
18
+ # @return [HashWithIndifferentAccess{Symbol => Symbol}]
19
+ def __getobj__
20
+ hash
21
+ end
22
+
23
+ # @overload {Delegator#__setobj__}
24
+ def __setobj__(_)
25
+ # noop
26
+ end
27
+
28
+ # @param key [#to_sym] The alias name of SchemaSet
29
+ # @param value [String, Symbol] The name of SchemaSet class
30
+ def []=(key, value)
31
+ raise TypeError, "key (#{key}) cannot be converted to a symbol" unless key.respond_to?(:to_sym)
32
+
33
+ if !value.is_a?(String) && !value.is_a?(Symbol)
34
+ raise TypeError,
35
+ "value (#{value}) must be the name of SchemaSet class"
36
+ end
37
+
38
+ hash[key.to_sym] = value.to_sym
39
+ end
40
+
41
+ # @return [SchemaSet]
42
+ def fetch_instance(key)
43
+ klass = fetch(key).constantize
44
+
45
+ raise TypeError, "#{klass} is not the name of SchemaSet class" unless klass < JsonSchemaView::SchemaSet
46
+
47
+ klass.new
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchemaView
4
+ # The singleton holds the configuration for the gem.
5
+ # it can be accessed by both its class methods and Rails's configuration.
6
+ class Configuration
7
+ require_relative "configuration/schema_set_dictionary"
8
+
9
+ class << self
10
+ # @return [JsonSchemaView::Configuration]
11
+ def instance
12
+ @instance ||= new
13
+ end
14
+
15
+ # @yield [configuration]
16
+ # @yieldparam configuration [JsonSchemaView::Configuration]
17
+ def configure(&block)
18
+ instance.configure(&block)
19
+ end
20
+ end
21
+
22
+ def initialize
23
+ @schema_sets = SchemaSetDictionary.new
24
+ @validate_by_default = false
25
+ end
26
+
27
+ # @return [SchemaSetDictionary{Symbol => Symbol}] The renderers.
28
+ attr_reader :schema_sets
29
+
30
+ # @return [Boolean] Whether if validate components with its schema on render by default.
31
+ attr_accessor :validate_by_default
32
+
33
+ # @param new_sets [Hash{String, Symbol => String, Symbol}]
34
+ def schema_sets=(new_sets)
35
+ @schema_sets = SchemaSetDictionary.new(new_sets)
36
+ end
37
+
38
+ # @yield [configuration]
39
+ # @yieldparam configuration [JsonSchemaView::Configuration]
40
+ def configure
41
+ yield self
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json_world"
4
+
5
+ require_relative "json_world_extensions"
6
+
7
+ module JsonSchemaView
8
+ # @abstract
9
+ module JsonSchemaDefinable
10
+ extend ActiveSupport::Concern
11
+
12
+ include ::JsonWorld::DSL
13
+ include JsonWorldExtensions::Schema202012
14
+ include JsonWorldExtensions::CompactOptionalProperties
15
+ include JsonWorldExtensions::Camelizable
16
+ include JsonWorldExtensions::Validatable
17
+
18
+ included do
19
+ additional_properties(false)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+
5
+ module JsonSchemaView
6
+ module JsonWorldExtensions
7
+ # Define JSON Schema's additionalProperties property.
8
+ # @see https://json-schema.org/understanding-json-schema/reference/object.html#additional-properties
9
+ #
10
+ # @example
11
+ # class Zoo
12
+ # include JsonWorld::DSL
13
+ # include JsonSchemaView::JsonWorldExtensions::MapType::DSL
14
+ #
15
+ # additional_properties(false)
16
+ # property(
17
+ # :dogMap,
18
+ # type: map_type(Dog),
19
+ # )
20
+ # end
21
+ module AdditionalProperties
22
+ extend ActiveSupport::Concern
23
+
24
+ class_methods do
25
+ # @override {Class.override}
26
+ def inherited(child)
27
+ super
28
+ child.additional_properties(additional_properties)
29
+ end
30
+
31
+ # Return the additionalProperties property.
32
+ # Set the additionalProperties property if arguments are given.
33
+ # @see https://json-schema.org/draft/2020-12/json-schema-core.html#additionalProperties
34
+ # @see https://json-schema.org/understanding-json-schema/reference/object.html#id5
35
+ #
36
+ # @param value [false, Hash]
37
+ # @param value_keywords [Hash]
38
+ def additional_properties(value = nil, **value_keywords)
39
+ return @additional_properties = value unless value.nil?
40
+ return @additional_properties = value_keywords unless value_keywords.empty?
41
+
42
+ @additional_properties
43
+ end
44
+
45
+ # @override {JsonWorld::DSL::ClassMethods#as_json_schema}
46
+ def as_json_schema
47
+ # Do not allow undefined properities.
48
+ # @see https://json-schema.org/understanding-json-schema/reference/object.html#additionalproperties
49
+ if @additional_properties.nil?
50
+ super
51
+ else
52
+ super.merge("additionalProperties": @additional_properties)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchemaView
4
+ module JsonWorldExtensions
5
+ # This class implements `anyOf` schema composition.
6
+ # Instances of this class acts as an json world compatible object and prints the schema for anyOf combination.
7
+ # @see https://json-schema.org/understanding-json-schema/reference/combining.html#id6
8
+ # @example
9
+ # class Zoo
10
+ # include JsonWorld::DSL
11
+ # include JsonSchemaView::JsonWorldExtensions::MapType::DSL
12
+ # property(
13
+ # :animal,
14
+ # type: any_of.new(Dog, Cat),
15
+ # )
16
+ # end
17
+ class AnyOf
18
+ module DSL
19
+ extend ActiveSupport::Concern
20
+
21
+ class_methods do
22
+ def any_of(*types)
23
+ JsonWorldExtensions::AnyOf.new(*types)
24
+ end
25
+ end
26
+ end
27
+
28
+ attr_reader :types
29
+
30
+ def initialize(*types)
31
+ @types = types
32
+ end
33
+
34
+ def as_json_schema
35
+ { "anyOf" => types.map(&:as_json_schema) }
36
+ end
37
+
38
+ alias as_json_schema_without_links as_json_schema
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+
5
+ module JsonSchemaView
6
+ module JsonWorldExtensions
7
+ # Make the object to be serialized with camelized properties.
8
+ module Camelizable
9
+ extend ActiveSupport::Concern
10
+
11
+ class_methods do
12
+ # @param (see JsonWorld::DSL::ClassMethods#property)
13
+ # @param camelize [Boolean] if true, camelize the property name on json format.
14
+ def property(raw_property_name, camelize: true, **options)
15
+ raw_property_name = raw_property_name.to_sym
16
+ property_name = camelize ? camelize_name(raw_property_name) : raw_property_name
17
+
18
+ super(property_name, **options)
19
+
20
+ # Define a method with camelized name as an alias of the method with raw name.
21
+ if camelize && property_name != raw_property_name
22
+ define_method(property_name) do
23
+ public_send(raw_property_name)
24
+ end
25
+ end
26
+ end
27
+
28
+ # @param name [String, Symbol]
29
+ # @return [Symbol]
30
+ def camelize_name(name)
31
+ ActiveSupport::Inflector.camelize(name.to_s, false).to_sym
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchemaView
4
+ module JsonWorldExtensions
5
+ # This module automatically removes properties with null value from encoded json if the property is optional.
6
+ #
7
+ # JSON Schema distinguishs a optional property and a nullable property.
8
+ # If the value of a optional property is empty, you should remove the property from the encoded json.
9
+ # This module make safe such the optional properties.
10
+ # @see https://json-schema.org/understanding-json-schema/reference/object.html#required-properties
11
+ module CompactOptionalProperties
12
+ # @note Overrides {JsonWorld::JsonEncodable#properties}
13
+ def properties(options)
14
+ optional_property_names = self.class.property_definitions.select(&:optional?).map(&:property_name)
15
+
16
+ super(options).reject { |key, value| value.nil? && optional_property_names.include?(key) }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchemaView
4
+ module JsonWorldExtensions
5
+ # This module allows {JsonWorld::DSL::ClassMethods#property} to define constant values.
6
+ # Defined constant values are reflect to JSON Schema.
7
+ # @see https://json-schema.org/understanding-json-schema/reference/generic.html#constant-values
8
+ module ConstantProperty
9
+ extend ActiveSupport::Concern
10
+
11
+ class_methods do
12
+ # If property is defined with `const` parameter, define an instance method to return the value.
13
+ # @note Overrides {JsonWorld::DSL::ClassMethods#property}
14
+ def property(name, **options)
15
+ if options[:const]
16
+ const = options[:const].freeze
17
+ define_method(name) { const }
18
+ end
19
+
20
+ super(name, **options)
21
+ end
22
+
23
+ # Add constant values informations JSON Schema
24
+ # @note Overrides {JsonWorld::DSL::ClassMethods#as_json_schema}
25
+ def as_json_schema
26
+ property_hash = property_definitions.map do |property|
27
+ if (const = property.raw_options[:const])
28
+ # For now, use enumerated values instead of constant values.
29
+ [property.property_name, { const: const }]
30
+ else
31
+ nil
32
+ end
33
+ end.compact.to_h
34
+ super.deep_merge(properties: property_hash)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchemaView
4
+ module JsonWorldExtensions
5
+ # Add methods to declare a common schema. Declared schema are exported as `$defs` property.
6
+ #
7
+ # @see: https://json-schema.org/understanding-json-schema/structuring.html#defs
8
+ module Declarable
9
+ extend ::ActiveSupport::Concern
10
+
11
+ class_methods do
12
+ attr_writer :declarations
13
+
14
+ # @override {Class.inherited}
15
+ def inherited(child)
16
+ super
17
+ child.declarations = declarations.clone
18
+ end
19
+
20
+ # @param type_or_name [Class<JsonWorld::DSL>, Symbol]
21
+ # @param (see JsonWorld::DSL::ClassMethods#property)
22
+ def declare(type_or_name, **options)
23
+ property_type = options[:type] || type_or_name
24
+ property_name = type_or_name.is_a?(Module) ? type_or_name.name.demodulize.to_sym : type_or_name.to_sym
25
+
26
+ declaration = JsonWorld::PropertyDefinition.new(property_name: property_name, type: property_type, **options)
27
+ declarations << declaration
28
+ end
29
+
30
+ # @override {JsonWorld::DSL::ClassMethods#as_json_schema}
31
+ def as_json_schema
32
+ decls = declarations_as_json_schema
33
+ if decls.present?
34
+ super.merge("$defs": decls)
35
+ else
36
+ super
37
+ end
38
+ end
39
+
40
+ def declarations_as_json_schema
41
+ declarations.inject({}) do |result, declaration|
42
+ result.merge(
43
+ declaration.property_name => declaration.as_json_schema,
44
+ )
45
+ end
46
+ end
47
+
48
+ # @return [Array<PropertyDefinition>]
49
+ def declarations
50
+ @declarations ||= []
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchemaView
4
+ module JsonWorldExtensions
5
+ # This module allows {JsonWorld::DSL::ClassMethods#property} to define enum values.
6
+ # Defined constant values are reflect to JSON Schema.
7
+ # @see https://json-schema.org/understanding-json-schema/reference/generic.html#enumerated-values
8
+ # @example
9
+ # class Zoo
10
+ # include JsonWorld::DSL
11
+ # include JsonSchemaView::JsonWorldExtensions::EnumType::DSL
12
+ # property(
13
+ # :animal,
14
+ # type: enum_type("Dog", "Cat"),
15
+ # )
16
+ # end
17
+ class EnumType
18
+ module DSL
19
+ extend ActiveSupport::Concern
20
+
21
+ class_methods do
22
+ def enum_type(*args)
23
+ JsonWorldExtensions::EnumType.new(*args)
24
+ end
25
+ end
26
+ end
27
+
28
+ attr_reader :candidates
29
+
30
+ # @param type [String, Symbol, #as_json_schema]
31
+ # @param candidates [Array<Object>]
32
+ def initialize(*candidates)
33
+ @candidates = candidates
34
+ end
35
+
36
+ def as_json_schema
37
+ {
38
+ enum: candidates
39
+ }
40
+ end
41
+
42
+ alias as_json_schema_without_links as_json_schema
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchemaView
4
+ module JsonWorldExtensions
5
+ # This class implements map type (string keys to values with the given type) in JSON Schema.
6
+ # You can specify the type of values but you cannot specify the type of keys,
7
+ # because JSON and JSON Schema only support String keys in objects.
8
+ #
9
+ # @see https://json-schema.org/understanding-json-schema/reference/object.html#additional-properties
10
+ #
11
+ # @example
12
+ # class Zoo
13
+ # include JsonWorld::DSL
14
+ # include JsonSchemaView::JsonWorldExtensions::MapType::DSL
15
+ # property(
16
+ # :dogMap,
17
+ # type: map_type(Dog),
18
+ # )
19
+ # end
20
+ class MapType
21
+ module DSL
22
+ extend ActiveSupport::Concern
23
+
24
+ class_methods do
25
+ def map_type(type)
26
+ JsonWorldExtensions::MapType.new(type)
27
+ end
28
+ end
29
+ end
30
+
31
+ attr_reader :type
32
+
33
+ def initialize(type)
34
+ @type = type
35
+ end
36
+
37
+ def as_json_schema
38
+ {
39
+ type: "object",
40
+ additionalProperties: JsonWorld::PropertyDefinition.new(type: type).as_json_schema
41
+ }
42
+ end
43
+
44
+ alias as_json_schema_without_links as_json_schema
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "json-schema"
5
+
6
+ module JsonSchemaView
7
+ module JsonWorldExtensions
8
+ # Add method to validate self properties with {JSON::Validator}.
9
+ module Validatable
10
+ # @raise [JSON::Schema::ValidationError] if self is not valid.
11
+ # @return [void]
12
+ def validate_json!
13
+ JSON::Validator.validate!(self.class.as_json_schema, as_json)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+
5
+ module JsonSchemaView
6
+ # A collection of extensions for {JsonWorld::DSL} to support recent JSON Schema.
7
+ # @private
8
+ module JsonWorldExtensions
9
+ require_relative "json_world_extensions/additional_properties"
10
+ require_relative "json_world_extensions/any_of"
11
+ require_relative "json_world_extensions/camelizable"
12
+ require_relative "json_world_extensions/compact_optional_properties"
13
+ require_relative "json_world_extensions/constant_property"
14
+ require_relative "json_world_extensions/declarable"
15
+ require_relative "json_world_extensions/enum_type"
16
+ require_relative "json_world_extensions/map_type"
17
+ require_relative "json_world_extensions/validatable"
18
+
19
+ # @see https://json-schema.org/specification.html
20
+ module Schema202012
21
+ extend ActiveSupport::Concern
22
+
23
+ include AdditionalProperties
24
+ include AnyOf::DSL
25
+ include ConstantProperty
26
+ include Declarable
27
+ include EnumType::DSL
28
+ include MapType::DSL
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ Description:
2
+ Generates the configuration file (config/initializers/json_schema_view.rb) and setup components dir (app/components).:
3
+
4
+ Example:
5
+ `bin/rails generate json_schema_view:install`
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module JsonSchemaView
6
+ module Generators
7
+ # Install files to setup json_schema_view gem.
8
+ class InstallGenerator < Rails::Generators::Base
9
+ source_root File.expand_path("templates", __dir__)
10
+
11
+ class_option :components_path, type: :string, default: "app/components"
12
+ class_option :export_path, type: :string, default: "json_schema"
13
+ class_option :renderer_type, type: :string, default: "react_on_rails"
14
+
15
+ def create_initializer
16
+ template "initializer.rb", "config/initializers/json_schema_view.rb"
17
+ end
18
+
19
+ def create_base_classes
20
+ template "base_component.rb", File.join(components_path, "base_component.rb")
21
+ template "base_props.rb", File.join(components_path, "base_props.rb")
22
+ template "component_schema_set.rb", File.join(components_path, "component_schema_set.rb")
23
+ end
24
+
25
+ def create_exmaples
26
+ template "example/todo_list_component.rb", File.join(components_path, "example_todo_list_component.rb")
27
+ template "example/todo_item_resource.rb",
28
+ File.join(components_path, "example_todo_list_component", "todo_item_resource.rb")
29
+ end
30
+
31
+ private
32
+
33
+ def components_path
34
+ options[:components_path]
35
+ end
36
+
37
+ def export_path
38
+ options[:export_path]
39
+ end
40
+
41
+ def renderer_type
42
+ options[:renderer_type]
43
+ end
44
+
45
+ def schema_set_class_name
46
+ "ComponentSchemaSet"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json_schema_view"
4
+
5
+ # @abstract
6
+ class BaseComponent < ::JsonSchemaView::BaseComponent
7
+ # You can configure how this components is rendered.
8
+ #
9
+ # There are some preset renderers:
10
+ # * `:json` - serialize the component as json text.
11
+ # * `:react_on_rails` - render the component by using react_on_rails gem.
12
+ renderer_class(:<%= renderer_type %>)
13
+
14
+ def base_props_class
15
+ BaseProps
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json_schema_view"
4
+
5
+ # @abstract
6
+ class BaseProps < ::JsonSchemaView::BaseProps
7
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json_schema_view"
4
+
5
+ # Configure what resource to export its JSON Schema and where directory to export.
6
+ class <%= schema_set_class_name %> < ::JsonSchemaView::SchemaSet
7
+ # <%= schema_set_class_name %> looks up component classses in this directory.
8
+ def root_path
9
+ __dir__
10
+ end
11
+
12
+ # <%= schema_set_class_name %> exports JSON Schema of these component classes.
13
+ def resource_classes_to_export
14
+ [
15
+ # Export all component classes (except for BaseComopnent) in `root_path`.
16
+ *search_component_classes.excluding(BaseComponent),
17
+ # You can add extra classes including {JsonSchemaDefinable} here to export their JSON Schemas.
18
+ ]
19
+ end
20
+
21
+ # <%= schema_set_class_name %> exports JSON Schema to this directory.
22
+ def export_path
23
+ Rails.root.join("<%= export_path %>")
24
+ end
25
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json_schema_view"
4
+
5
+ class ExampleTodoListComponent
6
+ # This is an example definition of a resource.
7
+ #
8
+ # A class that includes {JsonSchemaView::JsonSchemaDefinable} can generate its JSON Schema
9
+ # and it can be used as a type in another resource's property.
10
+ class TodoItemResource
11
+ include JsonSchemaView::JsonSchemaDefinable
12
+
13
+ property(
14
+ :name,
15
+ description: "The title of TODO item.",
16
+ type: String,
17
+ )
18
+
19
+ property(
20
+ :done,
21
+ description: "Whether the TODO item is done or not.",
22
+ type: [TrueClass, FalseClass],
23
+ )
24
+
25
+ property(
26
+ :note,
27
+ description: "The additional description of TODO item.",
28
+ type: String,
29
+ optional: true,
30
+ )
31
+
32
+ # @param todo_item [Hash] A todo item ({ name: String, done: Boolean, note: String or nil }).
33
+ def initialize(todo_item)
34
+ @todo_item = todo_item
35
+ end
36
+
37
+ # @return [String] The title of TODO item.
38
+ def title
39
+ @todo_item[:title]
40
+ end
41
+
42
+ # @return [Boolean] Whether the TODO item is done or not.
43
+ def done
44
+ @todo_item[:done]
45
+ end
46
+
47
+ # @param note [String, nil] The additional description of TODO item.
48
+ def note
49
+ @todo_item[:note]
50
+ end
51
+ end
52
+ end