sober_swag 0.1.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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/config/rubocop_linter_action.yml +4 -0
  3. data/.github/workflows/lint.yml +15 -0
  4. data/.github/workflows/ruby.yml +33 -2
  5. data/.gitignore +4 -0
  6. data/.rubocop.yml +75 -1
  7. data/.ruby-version +1 -1
  8. data/README.md +154 -1
  9. data/bin/console +16 -15
  10. data/docs/serializers.md +203 -0
  11. data/example/.rspec +1 -0
  12. data/example/.ruby-version +1 -1
  13. data/example/Gemfile +9 -7
  14. data/example/Gemfile.lock +96 -79
  15. data/example/app/controllers/people_controller.rb +41 -23
  16. data/example/app/controllers/posts_controller.rb +110 -0
  17. data/example/app/models/application_record.rb +3 -0
  18. data/example/app/models/person.rb +6 -0
  19. data/example/app/models/post.rb +9 -0
  20. data/example/app/output_objects/person_errors_output_object.rb +5 -0
  21. data/example/app/output_objects/person_output_object.rb +15 -0
  22. data/example/app/output_objects/post_output_object.rb +10 -0
  23. data/example/bin/bundle +24 -20
  24. data/example/bin/rails +1 -1
  25. data/example/bin/rake +1 -1
  26. data/example/config/application.rb +11 -7
  27. data/example/config/environments/development.rb +0 -1
  28. data/example/config/environments/production.rb +3 -3
  29. data/example/config/puma.rb +5 -5
  30. data/example/config/routes.rb +3 -0
  31. data/example/config/spring.rb +4 -4
  32. data/example/db/migrate/20200311152021_create_people.rb +0 -1
  33. data/example/db/migrate/20200603172347_create_posts.rb +11 -0
  34. data/example/db/schema.rb +16 -7
  35. data/example/spec/rails_helper.rb +64 -0
  36. data/example/spec/requests/people/create_spec.rb +52 -0
  37. data/example/spec/requests/people/get_spec.rb +35 -0
  38. data/example/spec/requests/people/index_spec.rb +69 -0
  39. data/example/spec/spec_helper.rb +94 -0
  40. data/lib/sober_swag.rb +6 -3
  41. data/lib/sober_swag/compiler/error.rb +2 -0
  42. data/lib/sober_swag/compiler/path.rb +2 -5
  43. data/lib/sober_swag/compiler/paths.rb +0 -1
  44. data/lib/sober_swag/compiler/type.rb +86 -56
  45. data/lib/sober_swag/controller.rb +16 -11
  46. data/lib/sober_swag/controller/route.rb +18 -21
  47. data/lib/sober_swag/controller/undefined_body_error.rb +3 -0
  48. data/lib/sober_swag/controller/undefined_path_error.rb +3 -0
  49. data/lib/sober_swag/controller/undefined_query_error.rb +3 -0
  50. data/lib/sober_swag/input_object.rb +28 -0
  51. data/lib/sober_swag/nodes/array.rb +1 -1
  52. data/lib/sober_swag/nodes/base.rb +5 -3
  53. data/lib/sober_swag/nodes/binary.rb +2 -1
  54. data/lib/sober_swag/nodes/enum.rb +4 -2
  55. data/lib/sober_swag/nodes/list.rb +0 -1
  56. data/lib/sober_swag/nodes/primitive.rb +6 -5
  57. data/lib/sober_swag/output_object.rb +102 -0
  58. data/lib/sober_swag/output_object/definition.rb +30 -0
  59. data/lib/sober_swag/{blueprint → output_object}/field.rb +14 -4
  60. data/lib/sober_swag/{blueprint → output_object}/field_syntax.rb +2 -2
  61. data/lib/sober_swag/{blueprint → output_object}/view.rb +15 -6
  62. data/lib/sober_swag/parser.rb +9 -4
  63. data/lib/sober_swag/serializer.rb +5 -2
  64. data/lib/sober_swag/serializer/array.rb +12 -0
  65. data/lib/sober_swag/serializer/base.rb +50 -1
  66. data/lib/sober_swag/serializer/conditional.rb +19 -2
  67. data/lib/sober_swag/serializer/field_list.rb +29 -6
  68. data/lib/sober_swag/serializer/mapped.rb +15 -3
  69. data/lib/sober_swag/serializer/meta.rb +35 -0
  70. data/lib/sober_swag/serializer/optional.rb +17 -2
  71. data/lib/sober_swag/serializer/primitive.rb +4 -1
  72. data/lib/sober_swag/server.rb +83 -0
  73. data/lib/sober_swag/types.rb +3 -0
  74. data/lib/sober_swag/version.rb +1 -1
  75. data/sober_swag.gemspec +8 -4
  76. metadata +79 -47
  77. data/Gemfile.lock +0 -92
  78. data/example/person.json +0 -4
  79. data/example/test/controllers/.keep +0 -0
  80. data/example/test/fixtures/.keep +0 -0
  81. data/example/test/fixtures/files/.keep +0 -0
  82. data/example/test/fixtures/people.yml +0 -11
  83. data/example/test/integration/.keep +0 -0
  84. data/example/test/models/.keep +0 -0
  85. data/example/test/models/person_test.rb +0 -7
  86. data/example/test/test_helper.rb +0 -13
  87. data/lib/sober_swag/blueprint.rb +0 -113
  88. data/lib/sober_swag/path.rb +0 -8
  89. data/lib/sober_swag/path/integer.rb +0 -21
  90. data/lib/sober_swag/path/lit.rb +0 -41
  91. data/lib/sober_swag/path/literal.rb +0 -29
  92. data/lib/sober_swag/path/param.rb +0 -33
@@ -1,92 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- sober_swag (0.1.0)
5
- activesupport
6
- dry-struct (~> 1.0)
7
- dry-types (~> 1.2)
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- activesupport (6.0.2.1)
13
- concurrent-ruby (~> 1.0, >= 1.0.2)
14
- i18n (>= 0.7, < 2)
15
- minitest (~> 5.1)
16
- tzinfo (~> 1.1)
17
- zeitwerk (~> 2.2)
18
- coderay (1.1.2)
19
- concurrent-ruby (1.1.6)
20
- diff-lcs (1.3)
21
- docile (1.3.2)
22
- dry-configurable (0.11.3)
23
- concurrent-ruby (~> 1.0)
24
- dry-core (~> 0.4, >= 0.4.7)
25
- dry-equalizer (~> 0.2)
26
- dry-container (0.7.2)
27
- concurrent-ruby (~> 1.0)
28
- dry-configurable (~> 0.1, >= 0.1.3)
29
- dry-core (0.4.9)
30
- concurrent-ruby (~> 1.0)
31
- dry-equalizer (0.3.0)
32
- dry-inflector (0.2.0)
33
- dry-logic (1.0.6)
34
- concurrent-ruby (~> 1.0)
35
- dry-core (~> 0.2)
36
- dry-equalizer (~> 0.2)
37
- dry-struct (1.3.0)
38
- dry-core (~> 0.4, >= 0.4.4)
39
- dry-equalizer (~> 0.3)
40
- dry-types (~> 1.3)
41
- ice_nine (~> 0.11)
42
- dry-types (1.4.0)
43
- concurrent-ruby (~> 1.0)
44
- dry-container (~> 0.3)
45
- dry-core (~> 0.4, >= 0.4.4)
46
- dry-equalizer (~> 0.3)
47
- dry-inflector (~> 0.1, >= 0.1.2)
48
- dry-logic (~> 1.0, >= 1.0.2)
49
- i18n (1.8.2)
50
- concurrent-ruby (~> 1.0)
51
- ice_nine (0.11.2)
52
- method_source (0.9.2)
53
- minitest (5.14.0)
54
- pry (0.12.2)
55
- coderay (~> 1.1.0)
56
- method_source (~> 0.9.0)
57
- rake (13.0.1)
58
- rspec (3.9.0)
59
- rspec-core (~> 3.9.0)
60
- rspec-expectations (~> 3.9.0)
61
- rspec-mocks (~> 3.9.0)
62
- rspec-core (3.9.1)
63
- rspec-support (~> 3.9.1)
64
- rspec-expectations (3.9.0)
65
- diff-lcs (>= 1.2.0, < 2.0)
66
- rspec-support (~> 3.9.0)
67
- rspec-mocks (3.9.1)
68
- diff-lcs (>= 1.2.0, < 2.0)
69
- rspec-support (~> 3.9.0)
70
- rspec-support (3.9.2)
71
- simplecov (0.18.5)
72
- docile (~> 1.1)
73
- simplecov-html (~> 0.11)
74
- simplecov-html (0.12.2)
75
- thread_safe (0.3.6)
76
- tzinfo (1.2.6)
77
- thread_safe (~> 0.1)
78
- zeitwerk (2.3.0)
79
-
80
- PLATFORMS
81
- ruby
82
-
83
- DEPENDENCIES
84
- bundler (~> 2.0)
85
- pry
86
- rake (~> 13.0)
87
- rspec (~> 3.0)
88
- simplecov
89
- sober_swag!
90
-
91
- BUNDLED WITH
92
- 2.1.2
@@ -1,4 +0,0 @@
1
- {
2
- "first_name": "Tony",
3
- "last_name": "Super"
4
- }
File without changes
File without changes
File without changes
@@ -1,11 +0,0 @@
1
- # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
-
3
- one:
4
- first_name: MyText
5
- last_name: MyText
6
- date_of_birth: 2020-03-11 09:20:21
7
-
8
- two:
9
- first_name: MyText
10
- last_name: MyText
11
- date_of_birth: 2020-03-11 09:20:21
File without changes
File without changes
@@ -1,7 +0,0 @@
1
- require 'test_helper'
2
-
3
- class PersonTest < ActiveSupport::TestCase
4
- # test "the truth" do
5
- # assert true
6
- # end
7
- end
@@ -1,13 +0,0 @@
1
- ENV['RAILS_ENV'] ||= 'test'
2
- require_relative '../config/environment'
3
- require 'rails/test_help'
4
-
5
- class ActiveSupport::TestCase
6
- # Run tests in parallel with specified workers
7
- parallelize(workers: :number_of_processors)
8
-
9
- # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
10
- fixtures :all
11
-
12
- # Add more helper methods to be used by all tests here...
13
- end
@@ -1,113 +0,0 @@
1
- require 'sober_swag/serializer'
2
-
3
- module SoberSwag
4
- ##
5
- # Create a serializer that is heavily inspired by the "Blueprinter" library.
6
- # This allows you to make "views" and such inside.
7
- #
8
- # Under the hood, this is actually all based on {SoberSwag::Serialzier::Base}.
9
- class Blueprint
10
- autoload(:Field, 'sober_swag/blueprint/field')
11
- autoload(:FieldSyntax, 'sober_swag/blueprint/field_syntax')
12
- autoload(:View, 'sober_swag/blueprint/view')
13
-
14
- ##
15
- # Use a Blueprint to define a new serializer.
16
- # It will be based on {SoberSwag::Serializer::Base}.
17
- #
18
- # An example is illustrative:
19
- #
20
- # PersonSerializer = SoberSwag::Blueprint.define do
21
- # field :id, primitive(:Integer)
22
- # field :name, primtive(:String).optional
23
- #
24
- # view :complex do
25
- # field :age, primitive(:Integer)
26
- # field :title, primitive(:String)
27
- # end
28
- # end
29
- #
30
- # Note: This currently will generate a new *class* that does serialization.
31
- # However, this is only a hack to get rid of the weird naming issue when
32
- # generating swagger from dry structs: their section of the schema area
33
- # is defined by their *Ruby Class Name*. In the future, if we get rid of this,
34
- # we might be able to keep this on the value-level, in which case {#define}
35
- # can simply return an *instance* of SoberSwag::Serializer that does
36
- # the correct thing, with the name you give it. This works for now, though.
37
- def self.define(&block)
38
- self.new.tap { |o|
39
- o.instance_eval(&block)
40
- }.serializer_class
41
- end
42
-
43
- def initialize(base_fields = [])
44
- @fields = base_fields.dup
45
- @views = []
46
- end
47
-
48
- attr_reader :fields, :views
49
-
50
- include FieldSyntax
51
-
52
- def add_field!(field)
53
- @fields << field
54
- end
55
-
56
- def view(name, &block)
57
- @views << View.define(name, fields, &block)
58
- end
59
-
60
- ##
61
- # Instead of generating a new value-level construct,
62
- # this will generate a new *class*. This is so that you can
63
- # name this blueprint, and have the views named as sub-classes.
64
- # This is important as the type compiler uses class names
65
- # for generating refs.
66
- def serializer_class
67
- @serializer_class ||= make_serializer_class!
68
- end
69
-
70
- private
71
-
72
- def make_serializer_class!
73
- # Klass we'll use
74
- klass = Class.new(SoberSwag::Serializer::Base)
75
- # The actual serialization logic is defined in a field list
76
- base_serializer = SoberSwag::Serializer::FieldList.new(fields)
77
- # WhateverBlueprint::Base is now used as the name for a ref
78
- klass.const_set(:Base, base_serializer.type)
79
- final_serializer = views.reduce(base_serializer) do |base, view|
80
- view_serializer = view.serializer
81
- # If we have a view :foo, its type is named
82
- # WhateverBlueprint::Foo
83
- klass.const_set(view.name.to_s.classify, view_serializer.type)
84
- SoberSwag::Serializer::Conditional.new(
85
- proc do |object, options|
86
- if options[:view].to_s == view.name.to_s
87
- [:left, object]
88
- else
89
- [:right, object]
90
- end
91
- end,
92
- view_serializer,
93
- base
94
- )
95
- end
96
- klass.send(:define_method, :serialize) do |object, options = {}|
97
- final_serializer.serialize(object, options)
98
- end
99
- klass.send(:define_method, :type) do
100
- final_serializer.type
101
- end
102
- klass.send(:define_singleton_method, :type) do
103
- final_serializer.type
104
- end
105
- klass.send(:define_singleton_method, :serializer) do
106
- klass.new
107
- end
108
-
109
- klass
110
- end
111
-
112
- end
113
- end
@@ -1,8 +0,0 @@
1
- module SoberSwag
2
- class Path
3
-
4
- autoload(:Lit, 'sober_swag/path/lit')
5
- autoload(:Param, 'sober_swag/path/param')
6
-
7
- end
8
- end
@@ -1,21 +0,0 @@
1
- module SoberSwag
2
- module Path
3
- class Integer < Node
4
-
5
- def initialize; end;
6
-
7
- def jumpable?
8
- true
9
- end
10
-
11
- def param?
12
- true
13
- end
14
-
15
- def param_type
16
- SoberSwag::Types::Paramter::Integer
17
- end
18
-
19
- end
20
- end
21
- end
@@ -1,41 +0,0 @@
1
- module SoberSwag
2
- class Path
3
- class Lit
4
- ##
5
- # Parse a literal path fragment
6
- def initialize(lit)
7
- @lit = lit
8
- end
9
-
10
- attr_reader :lit
11
-
12
- def param?
13
- false
14
- end
15
-
16
- def param_type
17
- nil
18
- end
19
-
20
- def param_key
21
- nil
22
- end
23
-
24
- ##
25
- # Constant to avoid a bunch of array allocation
26
- MATCH_SUCC = [:match, nil].freeze
27
- ##
28
- # Constant to avoid a bunch of array allocation
29
- MATHC_FAIL = [:fail].freeze
30
-
31
- def match(param)
32
- if param == lit
33
- MATCH_SUCC
34
- else
35
- MATCH_FAIL
36
- end
37
- end
38
-
39
- end
40
- end
41
- end
@@ -1,29 +0,0 @@
1
- module SoberSwag
2
- module Path
3
- ##
4
- # One literal text fragment, basically
5
- class Literal < Node
6
- ##
7
- # Make a new text node
8
- # @param text [String]
9
- def initialize(text)
10
- @text = text
11
- end
12
-
13
- attr_reader :text
14
-
15
- ##
16
- # We can make a jump table out of this node!
17
- def jumpable?
18
- true
19
- end
20
-
21
- ##
22
- # This doesn't read a parameter type.
23
- def param?
24
- false
25
- end
26
-
27
- end
28
- end
29
- end
@@ -1,33 +0,0 @@
1
- module SoberSwag
2
- class Path
3
- ##
4
- # Parse a parameter
5
- class Param
6
- def initialize(name, type)
7
- @name = name
8
- @type = type
9
- end
10
-
11
- def param?
12
- true
13
- end
14
-
15
- def param_key
16
- @name
17
- end
18
-
19
- def param_type
20
- @type
21
- end
22
-
23
- def match(param)
24
- if (m = @type.try(param)).success?
25
- [:match, m]
26
- else
27
- [:fail]
28
- end
29
- end
30
-
31
- end
32
- end
33
- end