sober_swag 0.1.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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