litl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 91ca010a8e051e74550f0c7a97a213b506c4af4ab8e074109b5038f1ca12e604
4
+ data.tar.gz: e3b43943c7eed36b0b620bb6e5fefcb30061c524c444682d07e47743139ae4f5
5
+ SHA512:
6
+ metadata.gz: e46d9e27b544ff868ddb0745c7fa86a6af2f1d099556ecebf2d5706843074391ccbb8378fb72d1ce63af0a8f1e87e95fd5897403a0ef10b61551f31a3c353ea0
7
+ data.tar.gz: 9795fbb6dad81644375ae5b6fa15c8ad890fc8e28e476dd309b8791587a3059a2ff3a2910e297dc9757c5abb64cf09ebcba718fd5636fb8c445a0b15fb01ae27
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .rspec_status
10
+ /.idea
11
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,23 @@
1
+ inherit_gem:
2
+ rubocop-config-umbrellio: lib/rubocop.yml
3
+ armitage-rubocop:
4
+ - lib/rubocop.general.yml
5
+ - lib/rubocop.rake.yml
6
+ - lib/rubocop.rspec.yml
7
+
8
+ AllCops:
9
+ TargetRubyVersion: 2.7.0
10
+ Include:
11
+ - lib/**/*.rb
12
+ - spec/**/*.rb
13
+ - Gemfile
14
+ - Rakefile
15
+ - lit.gemspec
16
+ - bin/console
17
+ - bin/compile
18
+
19
+ Style/AccessModifierDeclarations:
20
+ Enabled: false
21
+
22
+ Style/MultipleComparison:
23
+ Enabled: false
@@ -0,0 +1 @@
1
+ 2.5.5
@@ -0,0 +1,19 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ before_install: gem install bundler -v 2.1.2
5
+ script:
6
+ - bundle exec rake rubocop
7
+ - bundle exec rake rspec
8
+ jobs:
9
+ fast_finish: true
10
+ include:
11
+ - rvm: 2.7.0
12
+ os: [linux, osx]
13
+ - rvm: ruby-head
14
+ os: [linux, osx]
15
+ - rvm: jruby-head
16
+ os: [linux, osx]
17
+ allow_failures:
18
+ - rvm: ruby-head
19
+ - rvm: jruby-head
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
@@ -0,0 +1,89 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ litl (0.1.0)
5
+ litl-parser (= 0.1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ armitage-rubocop (0.79.0)
11
+ rubocop (= 0.79.0)
12
+ rubocop-performance (= 1.5.2)
13
+ rubocop-rails (= 2.4.1)
14
+ rubocop-rake (= 0.5.0)
15
+ rubocop-rspec (= 1.37.1)
16
+ ast (2.4.0)
17
+ coderay (1.1.2)
18
+ diff-lcs (1.3)
19
+ docile (1.3.2)
20
+ jaro_winkler (1.5.4)
21
+ json (2.3.0)
22
+ litl-parser (0.1.0)
23
+ method_source (0.9.2)
24
+ parallel (1.19.1)
25
+ parser (2.7.0.4)
26
+ ast (~> 2.4.0)
27
+ pry (0.12.2)
28
+ coderay (~> 1.1.0)
29
+ method_source (~> 0.9.0)
30
+ rack (2.2.2)
31
+ rainbow (3.0.0)
32
+ rake (13.0.1)
33
+ rspec (3.9.0)
34
+ rspec-core (~> 3.9.0)
35
+ rspec-expectations (~> 3.9.0)
36
+ rspec-mocks (~> 3.9.0)
37
+ rspec-core (3.9.1)
38
+ rspec-support (~> 3.9.1)
39
+ rspec-expectations (3.9.0)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.9.0)
42
+ rspec-mocks (3.9.0)
43
+ diff-lcs (>= 1.2.0, < 2.0)
44
+ rspec-support (~> 3.9.0)
45
+ rspec-support (3.9.1)
46
+ rubocop (0.79.0)
47
+ jaro_winkler (~> 1.5.1)
48
+ parallel (~> 1.10)
49
+ parser (>= 2.7.0.1)
50
+ rainbow (>= 2.2.2, < 4.0)
51
+ ruby-progressbar (~> 1.7)
52
+ unicode-display_width (>= 1.4.0, < 1.7)
53
+ rubocop-config-umbrellio (0.79.0.68)
54
+ rubocop (= 0.79.0)
55
+ rubocop-performance (= 1.5.2)
56
+ rubocop-rails (= 2.4.1)
57
+ rubocop-rspec (= 1.37.1)
58
+ rubocop-performance (1.5.2)
59
+ rubocop (>= 0.71.0)
60
+ rubocop-rails (2.4.1)
61
+ rack (>= 1.1)
62
+ rubocop (>= 0.72.0)
63
+ rubocop-rake (0.5.0)
64
+ rubocop
65
+ rubocop-rspec (1.37.1)
66
+ rubocop (>= 0.68.1)
67
+ ruby-progressbar (1.10.1)
68
+ simplecov (0.17.1)
69
+ docile (~> 1.1)
70
+ json (>= 1.8, < 3)
71
+ simplecov-html (~> 0.10.0)
72
+ simplecov-html (0.10.2)
73
+ unicode-display_width (1.6.1)
74
+
75
+ PLATFORMS
76
+ ruby
77
+
78
+ DEPENDENCIES
79
+ armitage-rubocop (~> 0.79)
80
+ bundler (~> 2.1)
81
+ litl!
82
+ pry (~> 0.12)
83
+ rake (~> 13.0)
84
+ rspec (~> 3.9)
85
+ rubocop-config-umbrellio (~> 0.79)
86
+ simplecov (~> 0.17)
87
+
88
+ BUNDLED WITH
89
+ 2.1.4
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019-2020 the 418
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.
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop"
6
+ require "rubocop/rake_task"
7
+ require "rubocop-performance"
8
+ require "rubocop-rspec"
9
+ require "rubocop-rake"
10
+
11
+ RuboCop::RakeTask.new(:rubocop) do |t|
12
+ config_path = File.expand_path(File.join(".rubocop.yml"), __dir__)
13
+ t.options = ["--config", config_path]
14
+ t.requires << "rubocop-performance"
15
+ t.requires << "rubocop-rspec"
16
+ t.requires << "rubocop-rake"
17
+ end
18
+
19
+ RSpec::Core::RakeTask.new(:rspec)
20
+
21
+ task default: :rspec
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'lit'
6
+
7
+ require 'pry'
8
+ Pry.start
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ module LIT
6
+ require "lit/parser"
7
+
8
+ require_relative "lit/version"
9
+ require_relative "lit/errors"
10
+ require_relative "lit/object"
11
+ require_relative "lit/builder"
12
+ require_relative "lit/loader"
13
+ require_relative "lit/type_checker"
14
+ require_relative "lit/utils"
15
+ require_relative "lit/module_observer"
16
+ require_relative "lit/serializer"
17
+ require_relative "lit/request_deserializer"
18
+
19
+ def self.load(dir)
20
+ Loader.new.load_directory(dir)
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LIT
4
+ # @api private
5
+ # @since 0.1.0
6
+ module Builder
7
+ require_relative "builder/array"
8
+ require_relative "builder/map"
9
+ require_relative "builder/option"
10
+ require_relative "builder/object"
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LIT
4
+ module Builder
5
+ # @api private
6
+ # @since 0.1.0
7
+ class Array
8
+ def initialize(mod, type)
9
+ @type_checker = TypeChecker.new(mod)
10
+ @type = type
11
+ end
12
+
13
+ def build
14
+ type_checker = @type_checker
15
+ type = @type
16
+
17
+ Class.new(::LIT::Object::Array) do
18
+ define_method(:check_type!) do |value|
19
+ type_checker.check_type!(type, value)
20
+ end
21
+
22
+ private(:check_type!)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LIT
4
+ module Builder
5
+ # @api private
6
+ # @since 0.1.0
7
+ class Map
8
+ def initialize(mod, key_type, value_type)
9
+ @type_checker = TypeChecker.new(mod)
10
+ @key_type = key_type
11
+ @value_type = value_type
12
+ end
13
+
14
+ def build
15
+ type_checker = @type_checker
16
+ key_type = @key_type
17
+ value_type = @value_type
18
+
19
+ Class.new(::LIT::Object::Map) do
20
+ define_method(:check_type!) do |key, value|
21
+ type_checker.check_type!(key_type, key)
22
+ type_checker.check_type!(value_type, value)
23
+ end
24
+
25
+ private(:check_type!)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LIT
4
+ module Builder
5
+ # @api private
6
+ # @since 0.1.0
7
+ class Object
8
+ AST = Parser::AST
9
+
10
+ def initialize(ast, target_module)
11
+ @ast = ast
12
+ @target_module = target_module
13
+ @type_checker = TypeChecker.new(target_module)
14
+ end
15
+
16
+ def build
17
+ @ast.statements.map { |stmt| build_statement(stmt) }
18
+ end
19
+
20
+ private
21
+
22
+ def build_statement(stmt)
23
+ if stmt.is_a?(AST::EndpointStatement)
24
+ build_endpoint(stmt)
25
+ elsif stmt.is_a?(AST::TypeDeclarationStatement::Struct)
26
+ build_struct(stmt)
27
+ elsif stmt.is_a?(AST::TypeDeclarationStatement::Enum)
28
+ build_enum(stmt)
29
+ elsif stmt.is_a?(AST::TypeDeclarationStatement::TypeAlias)
30
+ build_type_alias(stmt)
31
+ else
32
+ raise InvalidASTError, "invalid statement: #{stmt}"
33
+ end
34
+ end
35
+
36
+ def build_endpoint(endpoint)
37
+ request = make_type(endpoint.request)
38
+ response = make_type(endpoint.response)
39
+
40
+ working_module = @target_module
41
+ endpoint_namespace_stack = endpoint.name.split(".").map { |x| Utils.camelize(x) }
42
+ endpoint_namespace_stack.each do |namespace|
43
+ m = Module.new
44
+ Utils.const_reset(working_module, namespace, m)
45
+ working_module = m
46
+ end
47
+
48
+ Utils.const_reset(working_module, "Request", request)
49
+ Utils.const_reset(working_module, "Response", response)
50
+ Utils.const_reset(working_module, "DefinedIn", @target_module)
51
+ end
52
+
53
+ def build_struct(struct)
54
+ klass = make_struct(struct.fields)
55
+ Utils.const_reset(@target_module, struct.name, klass)
56
+ end
57
+
58
+ def build_enum(enum)
59
+ mod = make_enum(enum.variants)
60
+ Utils.const_reset(@target_module, enum.name, mod)
61
+ end
62
+
63
+ def build_type_alias(type_alias)
64
+ object = make_type(type_alias.type)
65
+ Utils.const_reset(@target_module, type_alias.name, object)
66
+ end
67
+
68
+ def make_struct(fields)
69
+ type_checker = @type_checker
70
+
71
+ Class.new(::LIT::Object::Struct) do
72
+ define_method(:initialize) do |args|
73
+ fields.each do |(field_name, field_type)|
74
+ value = args.fetch(field_name)
75
+ type_checker.check_type!(field_type, value)
76
+ instance_variable_set(:"@#{field_name}", value)
77
+ end
78
+ end
79
+
80
+ fields.keys.each do |field_name|
81
+ define_method(field_name) { instance_variable_get(:"@#{field_name}") }
82
+ end
83
+
84
+ define_singleton_method(:__fields__) do
85
+ fields.reduce({}) do |acc, (field_name, field_type)|
86
+ acc.merge(field_name => field_type)
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ # rubocop:disable Metrics/MethodLength
93
+ def make_enum(variants)
94
+ mod = Module.new do
95
+ include ::LIT::Object::Enum
96
+ end
97
+
98
+ variants.each do |(variant_name, variant)|
99
+ variant_name = Utils.camelize(variant_name)
100
+
101
+ if variant == AST::EnumVariant::Unit
102
+ Utils.const_reset(mod, variant_name, Module.new do
103
+ include ::LIT::Object::EnumVariant
104
+
105
+ define_singleton_method(:__parent__) { mod }
106
+ define_singleton_method(:__kind__) { :unit }
107
+ define_singleton_method(:__name__) { variant_name }
108
+ end)
109
+ elsif variant.is_a?(AST::EnumVariant::Struct)
110
+ klass = make_struct(variant.fields)
111
+ klass.include(::LIT::Object::EnumVariant)
112
+
113
+ klass.define_method(:__parent__) { mod }
114
+ klass.define_method(:__kind__) { :struct }
115
+ klass.define_singleton_method(:__kind__) { :struct }
116
+ klass.define_method(:__name__) { variant_name }
117
+
118
+ Utils.const_reset(mod, variant_name, klass)
119
+ else
120
+ raise InvalidASTError, "invalid enum variant type: #{variant}"
121
+ end
122
+ end
123
+
124
+ mod
125
+ end
126
+
127
+ def make_type(type)
128
+ object =
129
+ if type.is_a?(AST::Type::Primitive::Map)
130
+ Map.new(
131
+ @target_module,
132
+ type.key_type,
133
+ type.value_type,
134
+ ).build
135
+ elsif type.is_a?(AST::Type::Primitive::Option)
136
+ Option.new(@target_module, type.type).build
137
+ elsif type.is_a?(AST::Type::Primitive::Array)
138
+ Array.new(@target_module, type.type).build
139
+ elsif type.is_a?(AST::Type::AnonymousStruct)
140
+ make_struct(type.fields)
141
+ elsif type.is_a?(AST::Type::AnonymousEnum)
142
+ make_enum(type.variants)
143
+ elsif type == AST::Type::Primitive::String ||
144
+ type == AST::Type::Primitive::Integer ||
145
+ type == AST::Type::Primitive::Float ||
146
+ type == AST::Type::Primitive::Boolean
147
+ Module.new
148
+ elsif type.is_a?(AST::Type::Alias)
149
+ target_module = @target_module
150
+
151
+ Class.new do
152
+ define_singleton_method(:const_missing) do |name|
153
+ target_module.const_get(type.name).const_get(name)
154
+ end
155
+
156
+ define_method(:initialize) do |*args|
157
+ @inner = target_module.const_get(type.name).new(*args)
158
+ end
159
+
160
+ define_method(:method_missing) do |*args|
161
+ @inner.send(*args)
162
+ end
163
+ end
164
+ else
165
+ raise InvalidASTError, "invalid type: #{type}"
166
+ end
167
+
168
+ Utils.const_reset(object, "TYPE", type)
169
+
170
+ object
171
+ end
172
+ # rubocop:enable Metrics/MethodLength
173
+ end
174
+ end
175
+ end