action_schema 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1900a8787c395b5cfa7fce53e3feb8d049f33a08a0498c766d98c389aa1a30ca
4
+ data.tar.gz: b51df6ac12c67618e34ad5deed5d4615a751b4d1cf999d0b38cdf7aa063d29ed
5
+ SHA512:
6
+ metadata.gz: 9f5f8d04be3a8dfde7b46c06580446934e810b1f1486bfa5a73c3b586003d2fe5fbcad63507b4b33005f9bc4944e5570b141eb704fad20f5f61bfbe9603fec82
7
+ data.tar.gz: 4f9936bc68703ab3a0ad4dcd7e3a217cf022a4cdf2cf5859b47097e8e5b543be6c5220c558e9eb86583357f06335bd55482d78c545033c44210f21246d477f0c
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+
4
+ inherit_gem:
5
+ rubocop-rails-omakase: rubocop.yml
data/CHANGELOG.md ADDED
@@ -0,0 +1,53 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2024-12-08
11
+
12
+ ### Added
13
+
14
+ #### Core Features
15
+
16
+ - **Rendering:** Render data in controller actions with `schema_for`
17
+ - **Inline schemas:** Define schemas inline in controller actions
18
+ - **Controller schemas:** Define reusable schemas directly in controllers with `schema`
19
+ - **Class schemas:** Define global schemas in standalone schema classes inheriting from `ActionSchema::Base`
20
+
21
+ #### Field Definitions
22
+
23
+ - **Fields:** Define a field with `field` or `fields`
24
+ - **Conditional Fields:** Conditionally render fields using `if:` and `unless:`
25
+ - **Computed Fields:** Define dynamically calculated fields with `computed`
26
+ - **Omitting Fields:** Exclude fields with `omit`
27
+
28
+ #### Associations
29
+
30
+ - **Schema Associations:** Nest schemas using `association`. Supports inline, controller, and class schemas.
31
+
32
+ #### Context & Hooks
33
+
34
+ - **Contexts:** Pass additional context to schemas
35
+ - **Hooks:** Execute code before and after rendering with `before_render` and `after_render`
36
+ - **Transformation:** Transform data within hooks with `transform`
37
+
38
+ #### Configuration
39
+
40
+ - **Key Transformations:** Define global key transformations with `ActionSchema.configuration.transform_keys`
41
+ - **Base Class:** Define your own base class for schemas with `ActionSchema.configuration.base_class`
42
+
43
+ #### Rails Integration
44
+
45
+ - **Rails Integration:** Automatically include `ActionSchema::Controller` in Rails controllers via a Railtie.
46
+
47
+ #### Other
48
+
49
+ - 100% test coverage
50
+ - Comprehensive documentation
51
+
52
+ [Unreleased]: https://github.com/jtnegrotto/action_schema/compare/v0.1.0...HEAD
53
+ [0.1.0]: https://github.com/jtnegrotto/action_schema/releases/tag/v0.1.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Julien Negrotto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,269 @@
1
+ # ActionSchema
2
+
3
+ ActionSchema provides a flexible, Rails-friendly approach to rendering ~and
4
+ parsing~ (coming soon) structured data in your controllers.
5
+
6
+ ## Status: Experimental 🚧
7
+
8
+ **ActionSchema** is currently in early development. Its API is subject to
9
+ significant changes. If you do choose to use it, please:
10
+
11
+ * Lock the version in your Gemfile (e.g. `gem "action_schema", "= 0.1.0"`)
12
+ * Be prepared to update your code as the library evolves
13
+ * Refer to the [CHANGELOG](CHANGELOG.md) for updates
14
+ * [Report](https://github.com/jtnegrotto/action_schema/issues/new) any issues you encounter to help improve the library
15
+
16
+ ## Installation
17
+
18
+ Add the gem to your Gemfile:
19
+
20
+ ```bash
21
+ bundle add action_schema -v '= 0.1.0'
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### Defining Schemas
27
+
28
+ #### Inline Schemas
29
+
30
+ The simplest way to define a schema is inline in your controller action:
31
+
32
+ ```ruby
33
+ class UsersController < ApplicationController
34
+ def index
35
+ users = User.all
36
+ render json: schema_for(users) do
37
+ fields :id, :email
38
+ computed(:full_name) { |user| "#{user.first_name} #{user.last_name}" }
39
+ end
40
+ end
41
+ end
42
+ ```
43
+
44
+ This approach is ideal for quick, one-off schemas. Think of it as a step up from `as_json` with added flexibility and readability.
45
+
46
+ #### Controller Schemas
47
+
48
+ For reusable schemas, define them in your controller. This keeps your code DRY and allows schemas to be shared across multiple actions:
49
+
50
+ ```ruby
51
+ class UsersController < ApplicationController
52
+ schema :index do
53
+ fields :id, :email
54
+ computed(:full_name) { |user| "#{user.first_name} #{user.last_name}" }
55
+ end
56
+
57
+ def index
58
+ users = User.all
59
+ render json: schema_for(users, :index)
60
+ end
61
+ end
62
+ ```
63
+
64
+ **Tip:** Controller schemas are inherited by subclasses. This makes it easy to define a common schemas in a base controller.
65
+
66
+ #### Class Schemas
67
+
68
+ For global schemas, use schema classes:
69
+
70
+ ```ruby
71
+ class UserSchema < ActionSchema::Base
72
+ fields :id, :email
73
+ computed(:full_name) { |user| "#{user.first_name} #{user.last_name}" }
74
+ end
75
+ ```
76
+
77
+ You can use these in your controllers like so:
78
+
79
+ ```ruby
80
+ class UsersController < ApplicationController
81
+ def index
82
+ users = User.all
83
+ render json: schema_for(users, UserSchema)
84
+ end
85
+ end
86
+ ```
87
+
88
+ ### Schema Definition DSL
89
+
90
+ #### Fields
91
+
92
+ Regular fields are defined using the `field` and `fields` methods:
93
+
94
+ ```ruby
95
+ field :id
96
+ field :name
97
+ field :created_at
98
+ field :updated_at
99
+ ```
100
+
101
+ or
102
+
103
+ ```ruby
104
+ fields :id, :name, :created_at, :updated_at
105
+ ```
106
+
107
+ Fields can be conditionally rendered using the `if` and `unless` options:
108
+
109
+ ```ruby
110
+ field :email, if: ->(user) { user.email.present? }
111
+ field :phone, unless: ->(user) { user.phone.nil? }
112
+ ```
113
+
114
+ #### Omitting Fields
115
+
116
+ You can omit fields using the `omit` method:
117
+
118
+ ```ruby
119
+ omit :created_at, :updated_at
120
+ ```
121
+
122
+ This can be useful when your schema inherits fields from a superclass, but you
123
+ don't need all of them in a particular action.
124
+
125
+ #### Computed Fields
126
+
127
+ Computed fields are defined using the `computed` method:
128
+
129
+ ```ruby
130
+ computed(:full_name) { |user| "#{user.first_name} #{user.last_name}" }
131
+ ```
132
+
133
+ #### Associations
134
+
135
+ Association schemas are specified using the `association` method, and like
136
+ other schemas, these can be defined inline, at the controller level, or in a
137
+ schema class.
138
+
139
+ ##### Inline
140
+
141
+ ```ruby
142
+ schema do
143
+ fields :id, :email
144
+ association :posts do
145
+ fields :id, :title
146
+ end
147
+ end
148
+ ```
149
+
150
+ ##### Named Schema
151
+
152
+ ```ruby
153
+ schema :index do
154
+ fields :id, :email
155
+ association :posts, :post
156
+ end
157
+
158
+ schema :post do
159
+ fields :id, :title
160
+ end
161
+ ```
162
+
163
+ ##### Class Schema
164
+
165
+ ```ruby
166
+ class UserSchema < ActionSchema::Base
167
+ fields :id, :email
168
+ association :posts, PostSchema
169
+ end
170
+
171
+ class PostSchema < ActionSchema::Base
172
+ fields :id, :title
173
+ end
174
+ ```
175
+
176
+ #### Contexts
177
+
178
+ Computed fields can access contextual data:
179
+
180
+ ```ruby
181
+ computed(:is_current_user) { |user, context| user == context[:current_user] }
182
+ ```
183
+
184
+ In your controller, you can pass the context to `#schema_for`:
185
+
186
+ ```ruby
187
+ render json: schema_for(users, context: { current_user: current_user })
188
+ ```
189
+
190
+ Alternatively, you can define the context at the controller level:
191
+
192
+ ```ruby
193
+ class UsersController < ApplicationController
194
+ schema_context({ current_user: :current_user })
195
+ end
196
+ ```
197
+
198
+ Controller-level contexts are inherited, and are merged with contexts defined
199
+ in the subclass. Action-level contexts inherit from the controller-level
200
+ context, and are similarly merged. More specific contexts take precedence over
201
+ less specific ones.
202
+
203
+ #### Hooks
204
+
205
+ You can define hooks to run before or after rendering. The `before_render` hook
206
+ takes a block that receives the record or collection to be rendered. The
207
+ `after_render` hook takes a block that receives the rendered data. Both hooks
208
+ allow you to replace the data with a new value using the `transform` method:
209
+
210
+ ```ruby
211
+ schema :default do
212
+ fields :id, :email
213
+
214
+ before_render do |user|
215
+ user.email.downcase!
216
+ end
217
+
218
+ after_render do |data|
219
+ transform({ user: data })
220
+ end
221
+ end
222
+ ```
223
+
224
+ **Tip:** Keep in mind that hooks are run whether the rendered object is a
225
+ single record or a collection. Be sure to handle both cases as necessary.
226
+
227
+ ## Rationale
228
+
229
+ The main reason that **ActionSchema** exists is that I find serialization in
230
+ Rails to be a bit of a pain. While Rails' built-in serialization methods
231
+ (`as_json`) are fine for simple cases, they quickly fall apart when you need to
232
+ handle anything more complex. On the other hand, many serialization libraries
233
+ feel like overkill, requiring too much boilerplate for tasks that should be
234
+ straightforward.
235
+
236
+ I believe that serialization is fundamentally the controller's responsibility.
237
+ After all, you can't effectively optimize your queries if you don't know what
238
+ data will be used. Integrating serialization into the controller, close to the
239
+ query, makes it easier to reason about and ensures a tighter integration
240
+ between your data and its representation.
241
+
242
+ That said, I understand that not everyone shares this view. While
243
+ **ActionSchema** provides a seamless API for defining schemas entirely within
244
+ controllers, it also supports defining reusable schema classes outside of
245
+ controllers for those who prefer a more decoupled approach. My goal is to
246
+ strike a balance: to make serialization simple when you need it to be, while
247
+ remaining flexible enough to adapt to a variety of use cases and scenarios.
248
+
249
+ ## Development
250
+
251
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
252
+ `rake spec` to run the tests. You can also run `bin/console` for an interactive
253
+ prompt that will allow you to experiment.
254
+
255
+ To install this gem onto your local machine, run `bundle exec rake install`. To
256
+ release a new version, update the version number in `version.rb`, and then run
257
+ `bundle exec rake release`, which will create a git tag for the version, push
258
+ git commits and the created tag, and push the `.gem` file to
259
+ [rubygems.org](https://rubygems.org).
260
+
261
+ ## Contributing
262
+
263
+ Bug reports and pull requests are welcome on GitHub at
264
+ https://github.com/jtnegrotto/action_schema.
265
+
266
+ ## License
267
+
268
+ The gem is available as open source under the terms of the [MIT
269
+ License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,151 @@
1
+ module ActionSchema
2
+ class FieldError < ActionSchema::Error
3
+ def initialize(field, record)
4
+ @field = field
5
+ @record = record
6
+ super("Field '#{field}' does not exist on record: #{record.inspect}")
7
+ end
8
+ end
9
+
10
+ class Base
11
+ class << self
12
+ attr_accessor :schema, :before_render_hooks, :after_render_hooks
13
+
14
+ def call(*args, **kwargs, &block)
15
+ new(*args, **kwargs, &block).render
16
+ end
17
+
18
+ def before_render(&block)
19
+ self.before_render_hooks ||= []
20
+ before_render_hooks << block
21
+ end
22
+
23
+ def after_render(&block)
24
+ self.after_render_hooks ||= []
25
+ after_render_hooks << block
26
+ end
27
+
28
+ def inherited(subclass)
29
+ subclass.before_render_hooks = (before_render_hooks || []).dup
30
+ subclass.after_render_hooks = (after_render_hooks || []).dup
31
+ subclass.schema = schema.dup
32
+ end
33
+
34
+ def field(name, value = nil, **options, &block)
35
+ schema[name] = { value: block || value || name, **options }
36
+ end
37
+
38
+ def association(name, schema_definition = nil, &block)
39
+ base_schema_class = ActionSchema.configuration.base_class
40
+
41
+ resolved_schema =
42
+ if schema_definition.is_a?(Symbol)
43
+ ->(controller) { controller.resolve_schema(schema_definition) }
44
+ elsif schema_definition.is_a?(Class)
45
+ schema_definition
46
+ elsif block_given?
47
+ Class.new(base_schema_class, &block)
48
+ else
49
+ raise ArgumentError, "An association schema or block must be provided"
50
+ end
51
+
52
+ schema[name] = { association: resolved_schema }
53
+ end
54
+
55
+ def computed(name, &block)
56
+ schema[name] = { computed: true, value: block }
57
+ end
58
+
59
+ def fields(*names)
60
+ names.each { |name| field(name) }
61
+ end
62
+
63
+ def omit(*names)
64
+ names.each { |name| schema.delete(name) }
65
+ end
66
+
67
+ def schema
68
+ @schema ||= {}
69
+ end
70
+
71
+ def parse(data)
72
+ raise NotImplementedError, "Parsing is not yet implemented"
73
+ end
74
+ end
75
+
76
+ attr_reader :record_or_collection, :context, :controller
77
+
78
+ def initialize(record_or_collection, context: {}, controller: nil)
79
+ @record_or_collection = record_or_collection
80
+ @context = context
81
+ @controller = controller
82
+ end
83
+
84
+ def render
85
+ renderable = @record_or_collection
86
+ renderable = apply_hooks(:before_render, @record_or_collection)
87
+
88
+ output =
89
+ if renderable.respond_to?(:map)
90
+ renderable.map { |record| render_record(record) }
91
+ else
92
+ render_record(renderable)
93
+ end
94
+
95
+ apply_hooks(:after_render, output)
96
+ end
97
+
98
+ private
99
+
100
+ def render_record(record)
101
+ self.class.schema.each_with_object({}) do |(key, config), result|
102
+ if_condition = config[:if]
103
+ unless_condition = config[:unless]
104
+
105
+ next if if_condition && !instance_exec(record, &if_condition)
106
+ next if unless_condition && instance_exec(record, &unless_condition)
107
+
108
+ transformed_key = transform_key(key)
109
+
110
+ result[transformed_key] =
111
+ if config[:computed]
112
+ instance_exec(record, context, &config[:value])
113
+ elsif association = config[:association]
114
+ associated_record_or_collection = record.public_send(key)
115
+ if associated_record_or_collection.nil?
116
+ nil
117
+ else
118
+ resolved_schema = association.is_a?(Proc) ? association.call(controller) : association
119
+ child_context = context.merge(parent: record)
120
+ resolved_schema.new(record.public_send(key), context: child_context, controller: controller).render
121
+ end
122
+ else
123
+ if record.respond_to?(config[:value])
124
+ record.public_send(config[:value])
125
+ else
126
+ raise FieldError.new(config[:value], record)
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ def transform_key(key)
133
+ transform_keys = ActionSchema.configuration.transform_keys
134
+ transform_keys ? transform_keys.call(key) : key
135
+ end
136
+
137
+ def apply_hooks(type, data)
138
+ hooks = self.class.public_send("#{type}_hooks") || []
139
+ hooks.each do |hook|
140
+ @transformed = nil
141
+ instance_exec(data, &hook)
142
+ data = @transformed || data
143
+ end
144
+ data
145
+ end
146
+
147
+ def transform(data)
148
+ @transformed = data
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,29 @@
1
+ module ActionSchema
2
+ class Configuration
3
+ attr_accessor :base_class, :transform_keys, :type_serializers
4
+
5
+ def initialize
6
+ @base_class = ActionSchema::Base
7
+ @transform_keys = nil
8
+ @type_serializers = {}
9
+ end
10
+
11
+ def base_class
12
+ if @base_class.is_a?(String)
13
+ @base_class.constantize
14
+ else
15
+ @base_class
16
+ end
17
+ end
18
+ end
19
+
20
+ class << self
21
+ def configuration
22
+ @configuration ||= Configuration.new
23
+ end
24
+
25
+ def configure
26
+ yield(configuration)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,58 @@
1
+ module ActionSchema
2
+ module Controller
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :action_schemas, default: {}
7
+ class_attribute :default_schema_context, default: {}
8
+ end
9
+
10
+ class_methods do
11
+ def schema(name = :default, &block)
12
+ action_schemas[name] = Class.new(ActionSchema.configuration.base_class, &block)
13
+ end
14
+
15
+ def schema_context(context)
16
+ self.default_schema_context = self.default_schema_context.merge(context)
17
+ end
18
+ end
19
+
20
+ def schema_context
21
+ resolve_schema_context(self.class.default_schema_context)
22
+ end
23
+
24
+ def schema_for(record_or_collection, schema_name = :default, context: {}, &block)
25
+ combined_schema_context = schema_context.merge(resolve_schema_context(context))
26
+
27
+ schema_definition =
28
+ if block_given?
29
+ Class.new(ActionSchema.configuration.base_class, &block)
30
+ elsif schema_name.is_a?(Class)
31
+ schema_name
32
+ else
33
+ self.class.action_schemas[schema_name]
34
+ end
35
+
36
+ raise ArgumentError, "Schema `#{schema_name}` not defined" unless schema_definition
37
+
38
+ schema_definition.new(record_or_collection, context: combined_schema_context, controller: self).render
39
+ end
40
+
41
+ def resolve_schema(schema_name)
42
+ self.class.action_schemas[schema_name] ||
43
+ raise(ArgumentError, "Schema `#{schema_name}` not defined")
44
+ end
45
+
46
+ private
47
+
48
+ def resolve_schema_context(context)
49
+ context.transform_values do |value|
50
+ if value.is_a?(Proc)
51
+ instance_exec(&value)
52
+ else
53
+ value
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,9 @@
1
+ module ActionSchema
2
+ class Railtie < ::Rails::Railtie
3
+ initializer "action_schema.controller" do
4
+ ActiveSupport.on_load(:action_controller_base) do
5
+ include ActionSchema::Controller
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionSchema
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "active_support/core_ext/class/attribute"
5
+
6
+ module ActionSchema
7
+ class Error < StandardError; end
8
+ end
9
+
10
+ require_relative "action_schema/version"
11
+ require_relative "action_schema/configuration"
12
+ require_relative "action_schema/base"
13
+ require_relative "action_schema/controller"
14
+ require_relative "action_schema/railtie" if defined?(Rails)
@@ -0,0 +1,4 @@
1
+ module ActionSchema
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: action_schema
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Julien Negrotto
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.21'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.21'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rails-omakase
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.22'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.22'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-rails
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: ActionSchema provides a flexible, Rails-friendly approach to rendering
126
+ and parsing structured data in your controllers.
127
+ email:
128
+ - jtnegrotto@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".rspec"
134
+ - ".rubocop.yml"
135
+ - CHANGELOG.md
136
+ - LICENSE.txt
137
+ - README.md
138
+ - Rakefile
139
+ - lib/action_schema.rb
140
+ - lib/action_schema/base.rb
141
+ - lib/action_schema/configuration.rb
142
+ - lib/action_schema/controller.rb
143
+ - lib/action_schema/railtie.rb
144
+ - lib/action_schema/version.rb
145
+ - sig/action_schema.rbs
146
+ homepage: https://github.com/jtnegrotto/action_schema
147
+ licenses:
148
+ - MIT
149
+ metadata:
150
+ homepage_uri: https://github.com/jtnegrotto/action_schema
151
+ source_code_uri: https://github.com/jtnegrotto/action_schema
152
+ changelog_uri: https://github.com/jtnegrotto/action_schema/blob/master/CHANGELOG.md
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: 3.0.0
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubygems_version: 3.5.23
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: A lightweight schema library for Rails controllers.
172
+ test_files: []