action_figure 0.5.0 → 0.6.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.
@@ -38,6 +38,14 @@ module ActionFigure
38
38
  assert_status(:forbidden, result, msg)
39
39
  end
40
40
 
41
+ def assert_Conflict(result, msg = nil)
42
+ assert_status(:conflict, result, msg)
43
+ end
44
+
45
+ def assert_PaymentRequired(result, msg = nil)
46
+ assert_status(:payment_required, result, msg)
47
+ end
48
+
41
49
  private
42
50
 
43
51
  def assert_status(expected, result, msg)
@@ -23,7 +23,9 @@ module ActionFigure
23
23
  NoContent: :no_content,
24
24
  UnprocessableContent: :unprocessable_content,
25
25
  NotFound: :not_found,
26
- Forbidden: :forbidden
26
+ Forbidden: :forbidden,
27
+ Conflict: :conflict,
28
+ PaymentRequired: :payment_required
27
29
  }.freeze
28
30
 
29
31
  MATCHERS.each do |name, status|
@@ -32,8 +34,8 @@ module ActionFigure
32
34
  failure_message do |result|
33
35
  "expected result status to be #{status.inspect}, but got #{result[:status].inspect}"
34
36
  end
35
- failure_message_when_negated do |_result|
36
- "expected result status not to be #{status.inspect}"
37
+ failure_message_when_negated do
38
+ "expected result not to have status #{status.inspect}"
37
39
  end
38
40
  end
39
41
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionFigure
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
data/lib/action_figure.rb CHANGED
@@ -9,13 +9,14 @@ require_relative "action_figure/formatters/jsend"
9
9
  require_relative "action_figure/formatters/json_api"
10
10
  require_relative "action_figure/formatters/default"
11
11
  require_relative "action_figure/formatters/wrapped"
12
- require "concurrent/map"
13
12
 
14
13
  # ActionFigure provides explicit, purpose-driven operation classes for Rails controller actions.
15
14
  module ActionFigure
16
15
  extend Configuration
17
16
  extend FormatRegistry
18
17
 
18
+ class IndeterminantEntryPointError < StandardError; end
19
+
19
20
  register_formatter(jsend: Formatters::Jsend)
20
21
  register_formatter(jsonapi: Formatters::JsonApi)
21
22
  register_formatter(default: Formatters::Default)
@@ -1,4 +1,160 @@
1
+ # Type definitions for the ActionFigure gem
2
+
3
+ # Response hash returned by formatter methods
4
+ type ActionFigure::response = { json: Hash[Symbol, untyped], status: Symbol } | { status: Symbol }
5
+
6
+ # Error hash mapping field names to arrays of error messages
7
+ type ActionFigure::error_hash = Hash[Symbol, Array[String]]
8
+
1
9
  module ActionFigure
2
10
  VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
11
+
12
+ class IndeterminantEntryPointError < StandardError
13
+ end
14
+
15
+ extend Configuration
16
+ extend FormatRegistry
17
+
18
+ def self.[]: (?Symbol format) -> Module
19
+ def self.included: (Module base) -> void
20
+ def self.register_formatter: (**Module formatters) -> void
21
+ def self.clear_format_module_cache: (Symbol name) -> void
22
+
23
+ # Provides global configuration via ActionFigure.configure
24
+ module Configuration
25
+ class Settings
26
+ attr_accessor format: Symbol
27
+ attr_accessor whiny_extra_params: bool
28
+ attr_accessor api_version: untyped
29
+ attr_accessor activesupport_notifications: bool
30
+
31
+ def initialize: () -> void
32
+ def configure: () { (Settings) -> void } -> void
33
+ def register: (**Module formatters) -> void
34
+ end
35
+
36
+ def configure: () { (Settings) -> void } -> void
37
+ def configuration: () -> Settings
38
+ end
39
+
40
+ # Provides formatter registration and lookup
41
+ module FormatRegistry
42
+ class Formats
43
+ def initialize: () -> void
44
+ def register_formatter: (**Module formatters) -> void
45
+ def fetch: (Symbol name) -> Module
46
+ end
47
+
48
+ def register_formatter: (**Module formatters) -> void
49
+ def fetch: (Symbol name) -> Module
50
+ end
51
+
52
+ # Base module for response formatters
53
+ module Formatter
54
+ REQUIRED_METHODS: Array[Symbol]
55
+
56
+ def NoContent: () -> ActionFigure::response
57
+ end
58
+
59
+ # Validation pipeline and DSL mixed into action classes
60
+ module Core
61
+ # Cross-parameter rule helpers for dry-validation contracts
62
+ module CrossParamRuleHelpers
63
+ def exclusive_rule: (*Symbol fields, String message) -> void
64
+ def any_rule: (*Symbol fields, String message) -> void
65
+ def one_rule: (*Symbol fields, String message) -> void
66
+ def all_rule: (*Symbol fields, String message) -> void
67
+ end
68
+
69
+ # Class-level DSL extended into action classes
70
+ module ClassMethods
71
+ def params_schema: () { () -> void } -> void
72
+ def rules: () { () -> void } -> void
73
+ def entry_point: (Symbol name) -> void
74
+ def entry_point_name: () -> Symbol?
75
+ def api_version: (?untyped value) -> untyped
76
+ def contract: () -> untyped
77
+ end
78
+
79
+ def entry_point_name: () -> Symbol
80
+ def contract: () -> untyped
81
+ def validated_call: (**untyped kwargs) -> ActionFigure::response
82
+
83
+ # ActiveSupport::Notifications instrumentation
84
+ module Notifications
85
+ end
86
+ end
87
+
88
+ module Formatters
89
+ # Rails-style responses with { data: } envelope
90
+ module Default
91
+ include ActionFigure::Formatter
92
+
93
+ def Ok: (resource: untyped, ?meta: untyped?) -> ActionFigure::response
94
+ def Created: (resource: untyped, ?meta: untyped?) -> ActionFigure::response
95
+ def Accepted: (?resource: untyped?, ?meta: untyped?) -> ActionFigure::response
96
+ def UnprocessableContent: (errors: ActionFigure::error_hash) -> ActionFigure::response
97
+ def NotFound: (errors: ActionFigure::error_hash) -> ActionFigure::response
98
+ def Forbidden: (errors: ActionFigure::error_hash) -> ActionFigure::response
99
+ end
100
+
101
+ # JSend-formatted responses
102
+ module Jsend
103
+ include ActionFigure::Formatter
104
+
105
+ def Ok: (resource: untyped, ?meta: untyped?) -> ActionFigure::response
106
+ def Created: (resource: untyped, ?meta: untyped?) -> ActionFigure::response
107
+ def Accepted: (?resource: untyped?, ?meta: untyped?) -> ActionFigure::response
108
+ def UnprocessableContent: (errors: ActionFigure::error_hash) -> ActionFigure::response
109
+ def NotFound: (errors: ActionFigure::error_hash) -> ActionFigure::response
110
+ def Forbidden: (errors: ActionFigure::error_hash) -> ActionFigure::response
111
+ end
112
+
113
+ # JSON:API-formatted responses
114
+ module JsonApi
115
+ include ActionFigure::Formatter
116
+
117
+ def Ok: (resource: untyped, ?meta: untyped?) -> ActionFigure::response
118
+ def Created: (resource: untyped, ?meta: untyped?) -> ActionFigure::response
119
+ def Accepted: (?resource: untyped?, ?meta: untyped?) -> ActionFigure::response
120
+ def UnprocessableContent: (errors: ActionFigure::error_hash) -> ActionFigure::response
121
+ def NotFound: (errors: ActionFigure::error_hash) -> ActionFigure::response
122
+ def Forbidden: (errors: ActionFigure::error_hash) -> ActionFigure::response
123
+
124
+ # Simple resource serialization for JSON:API
125
+ class Resource
126
+ def self.serialize: (untyped resource) -> untyped
127
+ end
128
+ end
129
+
130
+ # Uniform { data:, errors:, status: } envelope
131
+ module Wrapped
132
+ include ActionFigure::Formatter
133
+
134
+ def Ok: (resource: untyped, ?meta: untyped?) -> ActionFigure::response
135
+ def Created: (resource: untyped, ?meta: untyped?) -> ActionFigure::response
136
+ def Accepted: (?resource: untyped?, ?meta: untyped?) -> ActionFigure::response
137
+ def UnprocessableContent: (errors: ActionFigure::error_hash) -> ActionFigure::response
138
+ def NotFound: (errors: ActionFigure::error_hash) -> ActionFigure::response
139
+ def Forbidden: (errors: ActionFigure::error_hash) -> ActionFigure::response
140
+ end
141
+ end
142
+
143
+ module Testing
144
+ # Minitest assertions for action response results
145
+ module Minitest
146
+ def assert_Ok: (ActionFigure::response result, ?String? msg) -> void
147
+ def assert_Created: (ActionFigure::response result, ?String? msg) -> void
148
+ def assert_Accepted: (ActionFigure::response result, ?String? msg) -> void
149
+ def assert_NoContent: (ActionFigure::response result, ?String? msg) -> void
150
+ def assert_UnprocessableContent: (ActionFigure::response result, ?String? msg) -> void
151
+ def assert_NotFound: (ActionFigure::response result, ?String? msg) -> void
152
+ def assert_Forbidden: (ActionFigure::response result, ?String? msg) -> void
153
+ end
154
+
155
+ # RSpec custom matchers (be_Ok, be_Created, etc.)
156
+ module RSpec
157
+ MATCHERS: Hash[Symbol, Symbol]
158
+ end
159
+ end
4
160
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_figure
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tad Thorley
@@ -38,6 +38,7 @@ files:
38
38
  - docs/custom-formatters.md
39
39
  - docs/integration-patterns.md
40
40
  - docs/response-formatters.md
41
+ - docs/status-codes.md
41
42
  - docs/testing.md
42
43
  - docs/validation.md
43
44
  - lib/action_figure.rb