camille 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d5aa31349909cebc62309be91631d632419b925d9a6ded594485dfa204e9170
4
- data.tar.gz: d1b1cb24a630a0c109fc1042636372cf193dd135f1ef17784f3907c1a169502e
3
+ metadata.gz: 2370ceb41fe8fdd701b99671f1d4d82678fc103218e96a10a52e60b9b2d1ad1f
4
+ data.tar.gz: ef8fe63ad679a1744fdef8c58971148d3642be0be2c5e23ff53b510dfef2b449
5
5
  SHA512:
6
- metadata.gz: 7d65f32be6f7d8beee2d22b9d5cf5ed4fc84fa91c925605c6aa0be09d51475211ddbee5e23f321892d0f46fa59878af2d9753e3daac7c1e62f2ccf285e8147b6
7
- data.tar.gz: f2195c3c54f6c571abeb2fa3b541160f734c1ecee6adfaec4bc4025ad0be820ae4235028a3c91427aec3c7cbdcc4ba19ba5f7a3e7cb530a3e943913b57955a78
6
+ metadata.gz: 6b8068692bd238a82cded511bad5e15d3f0993640a487b335cfd7d1592fe3c8cb45f88924753a1b580ae7448a59d58e423c29332842fa9be09472585bc810ea7
7
+ data.tar.gz: 71bc242a3a3fc9224c0d2e7d3598d9e4be378ff7b2a028e02b55833927cfb516d6309c44bbc7b2296b0b9b780ffe07458435e40a89a1953d6044a465621e7ef9
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ ## 0.4.1
4
+
5
+ ### Added
6
+
7
+ * Added utility types Pick and Omit
8
+
9
+ ### Fixed
10
+
11
+ * Prevent loader errors from being silently rescued by Rails in development environment
12
+
13
+ ## 0.4.0
14
+
15
+ The first stable release
data/Gemfile CHANGED
@@ -9,5 +9,4 @@ gem "rake", "~> 13.0"
9
9
 
10
10
  gem "rspec", "~> 3.0"
11
11
 
12
- gem "rails"
13
12
  gem "rspec-rails"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- camille (0.4.0)
4
+ camille (0.4.1)
5
5
  rails (>= 6.1, < 8)
6
6
 
7
7
  GEM
@@ -172,7 +172,6 @@ PLATFORMS
172
172
 
173
173
  DEPENDENCIES
174
174
  camille!
175
- rails
176
175
  rake (~> 13.0)
177
176
  rspec (~> 3.0)
178
177
  rspec-rails
data/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## Why?
4
4
 
5
- Traditionally, the JSON response from a Rails API server isn't typed. So even if we have TypeScript at the front-end, we still have little guarantee that our back-end would return the correct type and structure of data. In order to eliminate type mismatch between both ends, Camille provides a syntax for you to define type schema for your Rails API, and uses these schemas to generate the TypeScript functions for calling the API.
5
+ Traditionally, the JSON response from a Rails API server isn't typed. So even if we have TypeScript at the front-end, we still have little guarantee that our back-end would return the correct type and structure of data.
6
+
7
+ In order to eliminate type mismatch between both ends, Camille provides a syntax for you to define type schema for your Rails API, and uses these schemas to generate the TypeScript functions for calling the API.
6
8
 
7
9
  For example, an endpoint defined in Ruby, where `data` is a controller action,
8
10
 
@@ -84,6 +86,8 @@ data(params: {id: number}): Promise<{name: string}>
84
86
 
85
87
  Therefore, the front-end user is required to provide an `id` when they call this function. And they can expect to get a `name` from the response of this request. There are no more type mismatch between both ends.
86
88
 
89
+ The `params` type for an endpoint is required to be an object type, or a hash in Ruby, while `response` type can be any supported type, for example a `Boolean`.
90
+
87
91
  Camille will automatically add a Rails route for each endpoint. You don't need to do anything other than having the schema file in place.
88
92
 
89
93
  When defining an endpoint, you can also use `post` instead of `get` for non-idempotent requests. However, no other HTTP verbs are supported, because verbs in RESTful like `patch` and `delete` indicate what we do on resources, but in RPC-style design each request is merely a function call that does not concern RESTful resources.
@@ -153,12 +157,13 @@ params(
153
157
  number_literal: 1,
154
158
  string_literal: 'hello',
155
159
  # a custom type we defined above
156
- product: Product
160
+ product: Product,
161
+ # Pick and Omit use [] to enclose parameters instead of <>
162
+ pick: Pick[{a: 1, b: 2}, 'a' | 'b'],
163
+ omit: Omit[Product, 'id']
157
164
  )
158
165
  ```
159
166
 
160
- String literal types and probably enums are planned for the future.
161
-
162
167
  ### TypeScript generation
163
168
 
164
169
  After you have your types and schemas in place, you can visit `/camille/endpoints.ts` in development environment to have the TypeScript request functions generated.
@@ -235,6 +240,10 @@ object:
235
240
  [2]: Expected number, got "3".
236
241
  ```
237
242
 
243
+ ### Reloading
244
+
245
+ Everything in `config/camille/types` and `config/camille/schemas` will automatically reload after changes in development environment, just like other files in Rails.
246
+
238
247
  ## Development
239
248
 
240
249
  Run tests with `bundle exec rake`.
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem "rake", "~> 13.0"
6
+ gem "rspec", "~> 3.0"
7
+ gem "rspec-rails"
8
+
9
+ gem 'rails', '~> 6.1.0'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem "rake", "~> 13.0"
6
+ gem "rspec", "~> 3.0"
7
+ gem "rspec-rails"
8
+
9
+ gem 'rails', '~> 7.0.0'
@@ -35,6 +35,7 @@ module Camille
35
35
  end
36
36
 
37
37
  def process_action(*)
38
+ Camille::Loader.check_and_raise_exception
38
39
  if endpoint = camille_endpoint
39
40
  params.deep_transform_keys!{|key| key.to_s.underscore}
40
41
  super
@@ -41,11 +41,23 @@ module Camille
41
41
 
42
42
  def reload_types_and_schemas
43
43
  synchronize do
44
- Camille::Loader.loaded_types.clear
45
- Camille::Loader.loaded_schemas.clear
46
- @zeitwerk_loader.reload
47
- eager_load
48
- construct_controller_name_to_schema_map
44
+ begin
45
+ @exception = nil
46
+ Camille::Loader.loaded_types.clear
47
+ Camille::Loader.loaded_schemas.clear
48
+ @zeitwerk_loader.reload
49
+ eager_load
50
+ construct_controller_name_to_schema_map
51
+ rescue Exception => e
52
+ @exception = e
53
+ raise e
54
+ end
55
+ end
56
+ end
57
+
58
+ def check_and_raise_exception
59
+ if @exception
60
+ raise @exception
49
61
  end
50
62
  end
51
63
 
@@ -3,6 +3,7 @@ require 'action_controller'
3
3
  module Camille
4
4
  class MainController < ActionController::Base
5
5
  def endpoints_ts
6
+ Camille::Loader.check_and_raise_exception
6
7
  render plain: Camille::CodeGenerator.generate_ts
7
8
  end
8
9
  end
@@ -0,0 +1,51 @@
1
+ module Camille
2
+ # shared base class for Pick and Omit
3
+ class PickAndOmit < Camille::BasicType
4
+ class ArgumentError < ::ArgumentError; end
5
+
6
+ def initialize type, keys
7
+ @type = Camille::Type.instance(type)
8
+ case
9
+ when @type.is_a?(Camille::Types::Object)
10
+ @target_object = @type
11
+ when @type.is_a?(Camille::Type) && @type.underlying.is_a?(Camille::Types::Object)
12
+ @target_object = @type.underlying
13
+ else
14
+ raise ArgumentError.new("Currently onle an object type or an alias of object type is supported in #{klass_name}. Got #{type.inspect}.")
15
+ end
16
+
17
+ @keys = Camille::Type.instance(keys)
18
+ case
19
+ when @keys.is_a?(Camille::Types::StringLiteral)
20
+ @keys_array = [@keys.value].map(&:to_sym)
21
+ when @keys.is_a?(Camille::Types::Union)
22
+ unfolded = unfold_union(@keys).flatten
23
+ if unfolded.all?{|x| x.is_a?(Camille::Types::StringLiteral)}
24
+ @keys_array = unfolded.map(&:value).map(&:to_sym)
25
+ else
26
+ raise ArgumentError.new("The second argument of #{klass_name} has to be a string literal or an union of string literals. Got #{keys.inspect}.")
27
+ end
28
+ else
29
+ raise ArgumentError.new("The second argument of #{klass_name} has to be a string literal or an union of string literals. Got #{keys.inspect}.")
30
+ end
31
+ end
32
+
33
+ def literal
34
+ "#{klass_name}<#{@type.literal}, #{@keys.literal}>"
35
+ end
36
+
37
+ def self.[] type, keys
38
+ self.new type, keys
39
+ end
40
+
41
+ private
42
+ def unfold_union type
43
+ if type.is_a?(Camille::Types::Union)
44
+ [unfold_union(type.left), unfold_union(type.right)]
45
+ else
46
+ [type]
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -3,6 +3,8 @@ module Camille
3
3
  class NumberLiteral < Camille::BasicType
4
4
  class ArgumentError < ::ArgumentError; end
5
5
 
6
+ attr_reader :value
7
+
6
8
  def initialize value
7
9
  if value.is_a?(Integer) || value.is_a?(Float)
8
10
  @value = value
@@ -0,0 +1,20 @@
1
+ module Camille
2
+ module Types
3
+ class Omit < PickAndOmit
4
+ def check value
5
+ processed_object.check(value)
6
+ end
7
+
8
+ private
9
+ def klass_name
10
+ 'Omit'
11
+ end
12
+
13
+ def processed_object
14
+ fields = @target_object.fields.reject{|k, _| @keys_array.include?(k)}
15
+ Camille::Types::Object.new(fields)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Camille
2
+ module Types
3
+ class Pick < PickAndOmit
4
+ def check value
5
+ processed_object.check(value)
6
+ end
7
+
8
+ private
9
+ def klass_name
10
+ 'Pick'
11
+ end
12
+
13
+ def processed_object
14
+ fields = @target_object.fields.select{|k, _| @keys_array.include?(k)}
15
+ Camille::Types::Object.new(fields)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -3,6 +3,8 @@ module Camille
3
3
  class StringLiteral < Camille::BasicType
4
4
  class ArgumentError < ::ArgumentError; end
5
5
 
6
+ attr_reader :value
7
+
6
8
  def initialize value
7
9
  if value.is_a?(::String)
8
10
  @value = value
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Camille
4
- VERSION = "0.4.0"
4
+ VERSION = "0.4.1"
5
5
  end
data/lib/camille.rb CHANGED
@@ -17,6 +17,9 @@ require_relative "camille/types/tuple"
17
17
  require_relative "camille/types/any"
18
18
  require_relative "camille/types/number_literal"
19
19
  require_relative "camille/types/string_literal"
20
+ require_relative "camille/pick_and_omit"
21
+ require_relative "camille/types/pick"
22
+ require_relative "camille/types/omit"
20
23
  require_relative "camille/type"
21
24
  require_relative "camille/type_error"
22
25
  require_relative "camille/type_error_printer"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: camille
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - 辻彩
@@ -38,12 +38,15 @@ extensions: []
38
38
  extra_rdoc_files: []
39
39
  files:
40
40
  - ".rspec"
41
+ - CHANGELOG.md
41
42
  - Gemfile
42
43
  - Gemfile.lock
43
44
  - README.md
44
45
  - Rakefile
45
46
  - bin/console
46
47
  - bin/setup
48
+ - gemfiles/rails-6.1
49
+ - gemfiles/rails-7.0
47
50
  - lib/camille.rb
48
51
  - lib/camille/basic_type.rb
49
52
  - lib/camille/code_generator.rb
@@ -60,6 +63,7 @@ files:
60
63
  - lib/camille/line.rb
61
64
  - lib/camille/loader.rb
62
65
  - lib/camille/main_controller.rb
66
+ - lib/camille/pick_and_omit.rb
63
67
  - lib/camille/railtie.rb
64
68
  - lib/camille/schema.rb
65
69
  - lib/camille/schemas.rb
@@ -75,6 +79,8 @@ files:
75
79
  - lib/camille/types/number.rb
76
80
  - lib/camille/types/number_literal.rb
77
81
  - lib/camille/types/object.rb
82
+ - lib/camille/types/omit.rb
83
+ - lib/camille/types/pick.rb
78
84
  - lib/camille/types/string.rb
79
85
  - lib/camille/types/string_literal.rb
80
86
  - lib/camille/types/tuple.rb