ree 1.0.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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +21 -0
- data/README.md +474 -0
- data/Rakefile +8 -0
- data/bin/console +8 -0
- data/bin/setup +8 -0
- data/exe/ree +264 -0
- data/lib/ree/args.rb +34 -0
- data/lib/ree/bean_dsl.rb +24 -0
- data/lib/ree/cli/generate_package.rb +18 -0
- data/lib/ree/cli/generate_package_schema.rb +54 -0
- data/lib/ree/cli/generate_packages_schema.rb +17 -0
- data/lib/ree/cli/generate_template.rb +20 -0
- data/lib/ree/cli/init.rb +22 -0
- data/lib/ree/cli/spec_runner.rb +184 -0
- data/lib/ree/cli.rb +12 -0
- data/lib/ree/container.rb +67 -0
- data/lib/ree/contracts/arg_contracts/any.rb +15 -0
- data/lib/ree/contracts/arg_contracts/array_of.rb +52 -0
- data/lib/ree/contracts/arg_contracts/block.rb +15 -0
- data/lib/ree/contracts/arg_contracts/bool.rb +21 -0
- data/lib/ree/contracts/arg_contracts/eq.rb +28 -0
- data/lib/ree/contracts/arg_contracts/exactly.rb +28 -0
- data/lib/ree/contracts/arg_contracts/hash_of.rb +59 -0
- data/lib/ree/contracts/arg_contracts/ksplat.rb +141 -0
- data/lib/ree/contracts/arg_contracts/kwargs.rb +22 -0
- data/lib/ree/contracts/arg_contracts/nilor.rb +16 -0
- data/lib/ree/contracts/arg_contracts/none.rb +15 -0
- data/lib/ree/contracts/arg_contracts/optblock.rb +11 -0
- data/lib/ree/contracts/arg_contracts/or.rb +30 -0
- data/lib/ree/contracts/arg_contracts/range_of.rb +51 -0
- data/lib/ree/contracts/arg_contracts/set_of.rb +54 -0
- data/lib/ree/contracts/arg_contracts/splat.rb +297 -0
- data/lib/ree/contracts/arg_contracts/splat_of.rb +64 -0
- data/lib/ree/contracts/arg_contracts/squarable.rb +11 -0
- data/lib/ree/contracts/arg_contracts/subclass_of.rb +28 -0
- data/lib/ree/contracts/arg_contracts.rb +29 -0
- data/lib/ree/contracts/called_args_validator.rb +291 -0
- data/lib/ree/contracts/contract_definition.rb +142 -0
- data/lib/ree/contracts/contractable.rb +34 -0
- data/lib/ree/contracts/core.rb +17 -0
- data/lib/ree/contracts/engine.rb +71 -0
- data/lib/ree/contracts/engine_proxy.rb +13 -0
- data/lib/ree/contracts/errors/bad_contract_error.rb +4 -0
- data/lib/ree/contracts/errors/contract_error.rb +4 -0
- data/lib/ree/contracts/errors/error.rb +4 -0
- data/lib/ree/contracts/errors/return_contract_error.rb +4 -0
- data/lib/ree/contracts/method_decorator.rb +158 -0
- data/lib/ree/contracts/truncatable.rb +9 -0
- data/lib/ree/contracts/utils.rb +9 -0
- data/lib/ree/contracts/validators/array_validator.rb +51 -0
- data/lib/ree/contracts/validators/base_validator.rb +27 -0
- data/lib/ree/contracts/validators/class_validator.rb +17 -0
- data/lib/ree/contracts/validators/default_validator.rb +20 -0
- data/lib/ree/contracts/validators/hash_validator.rb +100 -0
- data/lib/ree/contracts/validators/proc_validator.rb +17 -0
- data/lib/ree/contracts/validators/range_validator.rb +17 -0
- data/lib/ree/contracts/validators/regexp_validator.rb +17 -0
- data/lib/ree/contracts/validators/valid_validator.rb +28 -0
- data/lib/ree/contracts/validators.rb +42 -0
- data/lib/ree/contracts.rb +45 -0
- data/lib/ree/core/link_validator.rb +42 -0
- data/lib/ree/core/object.rb +132 -0
- data/lib/ree/core/object_error.rb +9 -0
- data/lib/ree/core/object_link.rb +21 -0
- data/lib/ree/core/object_schema.rb +47 -0
- data/lib/ree/core/object_schema_builder.rb +110 -0
- data/lib/ree/core/package.rb +177 -0
- data/lib/ree/core/package_dep.rb +9 -0
- data/lib/ree/core/package_env_var.rb +12 -0
- data/lib/ree/core/package_loader.rb +95 -0
- data/lib/ree/core/package_schema.rb +27 -0
- data/lib/ree/core/package_schema_builder.rb +53 -0
- data/lib/ree/core/package_schema_loader.rb +170 -0
- data/lib/ree/core/packages_detector.rb +43 -0
- data/lib/ree/core/packages_schema.rb +19 -0
- data/lib/ree/core/packages_schema_builder.rb +50 -0
- data/lib/ree/core/packages_schema_loader.rb +95 -0
- data/lib/ree/core/packages_schema_locator.rb +27 -0
- data/lib/ree/core/packages_store.rb +32 -0
- data/lib/ree/core/path_helper.rb +104 -0
- data/lib/ree/dsl/build_package_dsl.rb +155 -0
- data/lib/ree/dsl/domain_error.rb +4 -0
- data/lib/ree/dsl/error_builder.rb +39 -0
- data/lib/ree/dsl/error_dsl.rb +27 -0
- data/lib/ree/dsl/import_dsl.rb +106 -0
- data/lib/ree/dsl/link_import_builder.rb +66 -0
- data/lib/ree/dsl/object_dsl.rb +319 -0
- data/lib/ree/dsl/object_hooks.rb +6 -0
- data/lib/ree/dsl/package_require.rb +44 -0
- data/lib/ree/error.rb +11 -0
- data/lib/ree/facades/packages_facade.rb +197 -0
- data/lib/ree/fn_dsl.rb +24 -0
- data/lib/ree/gen/init.rb +64 -0
- data/lib/ree/gen/package.rb +56 -0
- data/lib/ree/gen.rb +8 -0
- data/lib/ree/handlers/template_handler.rb +118 -0
- data/lib/ree/link_dsl.rb +175 -0
- data/lib/ree/object_compiler.rb +149 -0
- data/lib/ree/package_dsl.rb +34 -0
- data/lib/ree/rspec_link_dsl.rb +19 -0
- data/lib/ree/spec_runner/command_generator.rb +49 -0
- data/lib/ree/spec_runner/command_params.rb +9 -0
- data/lib/ree/spec_runner/runner.rb +200 -0
- data/lib/ree/spec_runner/spec_filename_matcher.rb +27 -0
- data/lib/ree/spec_runner/view.rb +30 -0
- data/lib/ree/spec_runner.rb +11 -0
- data/lib/ree/templates/init/.gitignore +1 -0
- data/lib/ree/templates/init/.irbrc +13 -0
- data/lib/ree/templates/init/.rspec +3 -0
- data/lib/ree/templates/init/.ruby-version +1 -0
- data/lib/ree/templates/init/Gemfile +7 -0
- data/lib/ree/templates/init/Packages.schema.json +1 -0
- data/lib/ree/templates/init/bin/console +5 -0
- data/lib/ree/templates/init/readme.md +2 -0
- data/lib/ree/templates/init/ree.setup.rb +21 -0
- data/lib/ree/templates/init/spec.init.rb +7 -0
- data/lib/ree/templates/package/.gitignore +0 -0
- data/lib/ree/templates/package/.rspec +2 -0
- data/lib/ree/templates/package/<%=package_subdir_name%>/<%=package_name%>/.gitkeep +0 -0
- data/lib/ree/templates/package/<%=package_subdir_name%>/<%=package_name%>.rb +15 -0
- data/lib/ree/templates/package/Package.schema.json +0 -0
- data/lib/ree/templates/package/bin/console +5 -0
- data/lib/ree/templates/package/spec/package_schema_spec.rb +14 -0
- data/lib/ree/templates/package/spec/spec_helper.rb +3 -0
- data/lib/ree/templates/template_detector.rb +35 -0
- data/lib/ree/templates/template_renderer.rb +55 -0
- data/lib/ree/utils/render_utils.rb +20 -0
- data/lib/ree/utils/string_utils.rb +29 -0
- data/lib/ree/version.rb +5 -0
- data/lib/ree.rb +279 -0
- data/sig/ree.rbs +4 -0
- metadata +199 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
class Ree::PackageSchemaLoader
|
|
7
|
+
# Sample Package.schema.json
|
|
8
|
+
# {
|
|
9
|
+
# "schema_type": "package",
|
|
10
|
+
# "ree_version": "1.2.3",
|
|
11
|
+
# "name": "accounts",
|
|
12
|
+
# "entry_path": "package/accounts.rb",
|
|
13
|
+
# "depends_on": [
|
|
14
|
+
# {
|
|
15
|
+
# "name": "clock",
|
|
16
|
+
# },
|
|
17
|
+
# {
|
|
18
|
+
# "name": "test_utils",
|
|
19
|
+
# }
|
|
20
|
+
# ],
|
|
21
|
+
# "env_vars": [
|
|
22
|
+
# {
|
|
23
|
+
# "name": "accounts.string_var",
|
|
24
|
+
# "doc": null
|
|
25
|
+
# },
|
|
26
|
+
# {
|
|
27
|
+
# "name": "accounts.integer_var",
|
|
28
|
+
# "doc": "integer value"
|
|
29
|
+
# }
|
|
30
|
+
# ],
|
|
31
|
+
# "objects": [
|
|
32
|
+
# {
|
|
33
|
+
# "name": "accounts_cfg",
|
|
34
|
+
# "schema": "schemas/accounts/accounts_cfg.schema.json"
|
|
35
|
+
# },
|
|
36
|
+
# {
|
|
37
|
+
# "name": "transaction",
|
|
38
|
+
# "schema": "schemas/accounts/transaction.schema.json"
|
|
39
|
+
# }
|
|
40
|
+
# ]
|
|
41
|
+
# }
|
|
42
|
+
|
|
43
|
+
Schema = Ree::PackageSchema
|
|
44
|
+
|
|
45
|
+
# @param [String] abs_schema_path Absolute path to package Package.schema.json file
|
|
46
|
+
# @param [Nilor[Ree::Package]] existing_package Loaded package
|
|
47
|
+
# @return [Ree::Package]
|
|
48
|
+
def call(abs_schema_path, existing_package = nil)
|
|
49
|
+
if !File.exists?(abs_schema_path)
|
|
50
|
+
raise Ree::Error.new("File not found: #{abs_schema_path}", :invalid_package_schema)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
json_schema = begin
|
|
54
|
+
JSON.load_file(abs_schema_path)
|
|
55
|
+
rescue
|
|
56
|
+
raise Ree::Error.new("Invalid content: #{abs_schema_path}", :invalid_package_schema)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
schema_type = json_schema.fetch(Schema::SCHEMA_TYPE)
|
|
60
|
+
|
|
61
|
+
if schema_type != Schema::PACKAGE
|
|
62
|
+
raise Ree::Error.new("Invalid schema type: #{abs_schema_path}", :invalid_package_schema)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
ree_version = json_schema.fetch(Schema::REE_VERSION)
|
|
66
|
+
entry_rpath = json_schema.fetch(Schema::ENTRY_PATH)
|
|
67
|
+
package_name = json_schema.fetch(Schema::NAME).to_sym
|
|
68
|
+
|
|
69
|
+
root_dir = if existing_package && existing_package.gem?
|
|
70
|
+
Ree.gem(existing_package.gem_name).dir
|
|
71
|
+
else
|
|
72
|
+
Ree.root_dir
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
schema_rpath = Pathname
|
|
76
|
+
.new(abs_schema_path)
|
|
77
|
+
.relative_path_from(Pathname.new(root_dir))
|
|
78
|
+
.to_s
|
|
79
|
+
|
|
80
|
+
object_store = {}
|
|
81
|
+
deps_store = {}
|
|
82
|
+
vars_store = {}
|
|
83
|
+
|
|
84
|
+
package = if existing_package
|
|
85
|
+
existing_package
|
|
86
|
+
.set_ree_version(ree_version)
|
|
87
|
+
.set_entry_rpath(entry_rpath)
|
|
88
|
+
.set_schema_rpath(schema_rpath)
|
|
89
|
+
else
|
|
90
|
+
Ree::Package.new(
|
|
91
|
+
ree_version,
|
|
92
|
+
package_name,
|
|
93
|
+
entry_rpath,
|
|
94
|
+
schema_rpath,
|
|
95
|
+
nil
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
package.set_schema_loaded
|
|
100
|
+
|
|
101
|
+
json_schema.fetch(Schema::OBJECTS).each do |item|
|
|
102
|
+
name = item[Schema::Objects::NAME].to_s
|
|
103
|
+
schema_rpath = item[Schema::Objects::SCHEMA].to_s
|
|
104
|
+
list = [name, schema_rpath]
|
|
105
|
+
|
|
106
|
+
if list.reject(&:empty?).size != list.size
|
|
107
|
+
raise Ree::Error.new("invalid object data for #{item.inspect}: #{abs_schema_path}", :invalid_package_schema)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if object_store.has_key?(name)
|
|
111
|
+
raise Ree::Error.new("duplicate object name for '#{item[:name]}': #{abs_schema_path}", :invalid_package_schema)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
object_store[name] = true
|
|
115
|
+
|
|
116
|
+
object = Ree::Object.new(
|
|
117
|
+
name.to_sym,
|
|
118
|
+
schema_rpath,
|
|
119
|
+
Ree::PathHelper.object_rpath(schema_rpath),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
object.set_package(package.name)
|
|
123
|
+
|
|
124
|
+
package.set_object(object)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
deps = json_schema.fetch(Schema::DEPENDS_ON).map do |item|
|
|
128
|
+
name = item[Schema::DependsOn::NAME].to_sym
|
|
129
|
+
list = [name]
|
|
130
|
+
|
|
131
|
+
if list.reject(&:empty?).size != list.size
|
|
132
|
+
raise Ree::Error.new("invalid depends_on for: #{item.inspect}", :invalid_package_schema)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
if deps_store.has_key?(name)
|
|
136
|
+
raise Ree::Error.new("duplicate depends_on name for '#{item[:name]}'", :invalid_package_schema)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
deps_store[name] = true
|
|
140
|
+
Ree::PackageDep.new(name)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
package.set_deps(deps)
|
|
144
|
+
|
|
145
|
+
env_vars = json_schema.fetch(Schema::ENV_VARS).map do |item|
|
|
146
|
+
name = item[Schema::EnvVars::NAME].to_s
|
|
147
|
+
doc = item[Schema::EnvVars::DOC]
|
|
148
|
+
list = [name]
|
|
149
|
+
|
|
150
|
+
if list.reject(&:empty?).size != list.size
|
|
151
|
+
raise Ree::Error.new("invalid env_var for: #{item.inspect}", :invalid_package_schema)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
if vars_store.has_key?(name)
|
|
155
|
+
raise Ree::Error.new("duplicate env_var name for '#{item[:name]}'", :invalid_package_schema)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
vars_store[name] = true
|
|
159
|
+
|
|
160
|
+
Ree::PackageEnvVar.new(name, doc)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
package.set_env_vars(env_vars)
|
|
164
|
+
|
|
165
|
+
tags = json_schema.fetch(Schema::TAGS)
|
|
166
|
+
package.set_tags(tags)
|
|
167
|
+
|
|
168
|
+
package
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
5
|
+
class Ree::PackagesDetector
|
|
6
|
+
# @param [String] dir Packages root dir
|
|
7
|
+
# @return [ArrayOf[{name: String, entry_path: String, package_schema_path: String, gem_name: Nilor[String]}]]
|
|
8
|
+
def call(dir, gem_name = nil)
|
|
9
|
+
if !Dir.exists?(dir)
|
|
10
|
+
raise Ree::Error.new("dir does not exist: #{dir}", :invalid_dir)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
files = File.join(dir, "**/", Ree::PACKAGE_SCHEMA_FILE)
|
|
14
|
+
names = {}
|
|
15
|
+
|
|
16
|
+
Dir[files].map do |file|
|
|
17
|
+
package_schema_path = Pathname
|
|
18
|
+
.new(file)
|
|
19
|
+
.relative_path_from(Pathname.new(dir))
|
|
20
|
+
.to_s
|
|
21
|
+
|
|
22
|
+
name = package_schema_path.split('/')[-2]
|
|
23
|
+
entry_path = Ree::PathHelper.package_entry_path(package_schema_path)
|
|
24
|
+
|
|
25
|
+
if !File.exists?(File.join(dir, entry_path))
|
|
26
|
+
Ree.logger.error("Entry file does not exist for '#{name}' package: #{entry_path}")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if names.has_key?(name)
|
|
30
|
+
raise Ree::Error.new("package '#{name}' has duplicate defintions.\n\t1) #{names[name]},\n\t2) #{entry_path}", :duplicate_package)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
names[name] = entry_path
|
|
34
|
+
|
|
35
|
+
{
|
|
36
|
+
name: name.to_sym,
|
|
37
|
+
entry_path: entry_path,
|
|
38
|
+
package_schema_path: package_schema_path,
|
|
39
|
+
gem_name: gem_name
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
module Ree::PackagesSchema
|
|
4
|
+
SCHEMA_TYPE = 'schema_type'
|
|
5
|
+
REE_VERSION = 'ree_version'
|
|
6
|
+
PACKAGES = 'packages'
|
|
7
|
+
GEM_PACKAGES = 'gem_packages'
|
|
8
|
+
|
|
9
|
+
module Packages
|
|
10
|
+
NAME = 'name'
|
|
11
|
+
SCHEMA = 'schema'
|
|
12
|
+
GEM = 'gem'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module GemPackages
|
|
16
|
+
NAME = 'name'
|
|
17
|
+
SCHEMA = 'schema'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
class Ree::PackagesSchemaBuilder
|
|
7
|
+
Schema = Ree::PackagesSchema
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@packages_detector = Ree::PackagesDetector.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @dir [String] - path to root project dir
|
|
14
|
+
def call
|
|
15
|
+
packages = @packages_detector.call(Ree.root_dir)
|
|
16
|
+
gem_packages = []
|
|
17
|
+
|
|
18
|
+
Ree.gems.each do |gem|
|
|
19
|
+
gem_packages += @packages_detector.call(gem.dir, gem.name)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
result = {
|
|
23
|
+
Schema::REE_VERSION => Ree::VERSION,
|
|
24
|
+
Schema::SCHEMA_TYPE => Schema::PACKAGES,
|
|
25
|
+
Schema::PACKAGES => packages.sort_by { _1[:name] }.map {
|
|
26
|
+
{
|
|
27
|
+
Schema::Packages::NAME => _1.fetch(:name),
|
|
28
|
+
Schema::Packages::SCHEMA => _1.fetch(:package_schema_path),
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
Schema::GEM_PACKAGES => gem_packages.sort_by { [_1.fetch(:gem_name), _1.fetch(:name)] }.map {
|
|
32
|
+
{
|
|
33
|
+
Schema::Packages::GEM => _1.fetch(:gem_name),
|
|
34
|
+
Schema::Packages::NAME => _1.fetch(:name),
|
|
35
|
+
Schema::Packages::SCHEMA => _1.fetch(:package_schema_path),
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
json = JSON.pretty_generate(result)
|
|
41
|
+
|
|
42
|
+
File.write(
|
|
43
|
+
File.join(Ree.root_dir, Ree::PACKAGES_SCHEMA_FILE),
|
|
44
|
+
json,
|
|
45
|
+
mode: 'w'
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
result
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
class Ree::PackagesSchemaLoader
|
|
6
|
+
# Sample Packages.schema.json
|
|
7
|
+
# {
|
|
8
|
+
# "schema_type": "packages",
|
|
9
|
+
# "ree_version": "1.2.3",
|
|
10
|
+
# "packages": [
|
|
11
|
+
# {
|
|
12
|
+
# "name": "accounts",
|
|
13
|
+
# "schema": "bc/accounts/Package.schema.json"
|
|
14
|
+
# },
|
|
15
|
+
# {
|
|
16
|
+
# "name": "tests",
|
|
17
|
+
# "schema": "bc/tests/Package.schema.json"
|
|
18
|
+
# }
|
|
19
|
+
# ]
|
|
20
|
+
# }
|
|
21
|
+
|
|
22
|
+
Schema = Ree::PackagesSchema
|
|
23
|
+
|
|
24
|
+
# @param [String] path Absolute path to Packages.schema.json file
|
|
25
|
+
# @param Nilor[Ree::PackagesStore] packages_store Existing packages store
|
|
26
|
+
# @return [Ree::PackagesStore]
|
|
27
|
+
def call(abs_schema_path, packages_store = nil, gem_name = nil)
|
|
28
|
+
if !File.exists?(abs_schema_path)
|
|
29
|
+
raise Ree::Error.new("File not found: #{abs_schema_path}", :invalid_packages_schema)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
schema = begin
|
|
33
|
+
JSON.load_file(abs_schema_path)
|
|
34
|
+
rescue
|
|
35
|
+
raise Ree::Error.new("Invalid content: #{abs_schema_path}", :invalid_packages_schema)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
schema_type = schema.fetch(Schema::SCHEMA_TYPE)
|
|
39
|
+
|
|
40
|
+
if schema_type != Schema::PACKAGES
|
|
41
|
+
raise Ree::Error.new("Invalid schema type: #{abs_schema_path}", :invalid_packages_schema)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
ree_version = schema.fetch(Schema::REE_VERSION)
|
|
45
|
+
data = schema.fetch(Schema::PACKAGES)
|
|
46
|
+
packages_store ||= Ree::PackagesStore.new(ree_version)
|
|
47
|
+
names = {}
|
|
48
|
+
|
|
49
|
+
data.each do |item|
|
|
50
|
+
name = item[Schema::Packages::NAME].to_s
|
|
51
|
+
schema_rpath = item[Schema::Packages::SCHEMA].to_s
|
|
52
|
+
list = [name, schema]
|
|
53
|
+
|
|
54
|
+
if list.reject(&:empty?).size != list.size
|
|
55
|
+
raise Ree::Error.new("invalid package data for: #{item.inspect}", :invalid_packages_schema)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if names.has_key?(name)
|
|
59
|
+
raise Ree::Error.new("duplicate package name for '#{item[:name]}'", :invalid_packages_schema)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
names[name] = true
|
|
63
|
+
|
|
64
|
+
package = Ree::Package.new(
|
|
65
|
+
ree_version,
|
|
66
|
+
name.to_sym,
|
|
67
|
+
Ree::PathHelper.package_entry_path(schema_rpath),
|
|
68
|
+
schema_rpath,
|
|
69
|
+
gem_name
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
existing = packages_store.get(package.name)
|
|
73
|
+
|
|
74
|
+
if existing && existing.gem_name != package.gem_name
|
|
75
|
+
if existing.gem_name.nil?
|
|
76
|
+
raise Ree::Error.new("Unable to add package `#{existing.name}` from `#{package.gem_name}` gem. Project has same package definition.", :duplicate_package)
|
|
77
|
+
else
|
|
78
|
+
raise Ree::Error.new("Unable to add package `#{existing.name}` from `#{package.gem_name}` gem. Package was already added from `#{existing.gem_name}` gem.", :duplicate_package)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
packages_store.add_package(
|
|
83
|
+
Ree::Package.new(
|
|
84
|
+
ree_version,
|
|
85
|
+
name.to_sym,
|
|
86
|
+
Ree::PathHelper.package_entry_path(schema_rpath),
|
|
87
|
+
schema_rpath,
|
|
88
|
+
gem_name
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
packages_store
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
class Ree::PackagesSchemaLocator
|
|
4
|
+
def call(path)
|
|
5
|
+
find_source_path_in_hierarchy(path)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def find_source_path_in_hierarchy(some_path)
|
|
11
|
+
some_path = File.expand_path(some_path)
|
|
12
|
+
|
|
13
|
+
raise Ree::Error.new("#{Ree::PACKAGES_SCHEMA_FILE} not found", :packages_json_not_found) if some_path == '/'
|
|
14
|
+
|
|
15
|
+
return potential_file(some_path) if present?(some_path)
|
|
16
|
+
|
|
17
|
+
find_source_path_in_hierarchy(File.dirname(some_path))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def present?(some_path)
|
|
21
|
+
File.exist?(potential_file(some_path))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def potential_file(some_path)
|
|
25
|
+
File.join(some_path, Ree::PACKAGES_SCHEMA_FILE)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
class Ree::PackagesStore
|
|
4
|
+
attr_reader :ree_version
|
|
5
|
+
|
|
6
|
+
def initialize(ree_version = Ree::VERSION)
|
|
7
|
+
@ree_version = ree_version
|
|
8
|
+
@store = {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def set_ree_version(val)
|
|
12
|
+
@ree_version = val; self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def packages
|
|
16
|
+
@store.values
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @param [Symbol] name
|
|
20
|
+
# @return [Ree::Package]
|
|
21
|
+
def get(name)
|
|
22
|
+
@store[name]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @param [Ree::Package] package
|
|
26
|
+
def add_package(package)
|
|
27
|
+
existing = get(package.name)
|
|
28
|
+
return existing if existing
|
|
29
|
+
|
|
30
|
+
@store[package.name] = package
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
5
|
+
class Ree::PathHelper
|
|
6
|
+
SCHEMAS_FOLDER = 'schemas'
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def abs_package_object_schemas_path(package)
|
|
10
|
+
root_dir = project_root_dir(package)
|
|
11
|
+
File.join(root_dir, SCHEMAS_FOLDER)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @param [Ree::Object] object
|
|
15
|
+
# @return [String] Absolute object file path
|
|
16
|
+
def abs_object_path(object)
|
|
17
|
+
package = Ree.container.packages_facade.get_package(object.package_name)
|
|
18
|
+
File.join(project_root_dir(package), object.rpath)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param [Ree::Object] object
|
|
22
|
+
# @return [String] Absolute object schema path
|
|
23
|
+
def abs_object_schema_path(object)
|
|
24
|
+
package = Ree.container.packages_facade.get_package(object.package_name)
|
|
25
|
+
File.join(project_root_dir(package), object.schema_rpath)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @param [String] schema_path Relative path of an object schema (ex. bc/accounts/schemas/accounts/object.schema.json)
|
|
29
|
+
# @return [String] Relative path to a object source file (ex. bc/accounts/object.rb)
|
|
30
|
+
def object_rpath(schema_rpath)
|
|
31
|
+
nodes = schema_rpath.split('/')
|
|
32
|
+
index = nodes.index(SCHEMAS_FOLDER)
|
|
33
|
+
nodes[index] = Ree::PACKAGE
|
|
34
|
+
object_name = nodes[-1].split('.').first
|
|
35
|
+
filename = "#{object_name}.rb"
|
|
36
|
+
nodes[-1] = filename
|
|
37
|
+
nodes.join('/')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @param [String] object_rpath Relative path of an object (bc/accounts/package/accounts/object.rb)
|
|
41
|
+
# @return [String] Relative path of a object schema (ex. bc/accounts/schemas/accounts/object.schema.json)
|
|
42
|
+
def object_schema_rpath(object_rpath)
|
|
43
|
+
nodes = object_rpath.split('/')
|
|
44
|
+
index = nodes.index(Ree::PACKAGE)
|
|
45
|
+
nodes[index] = Ree::SCHEMAS
|
|
46
|
+
filename = File.basename(nodes[-1], '.*')
|
|
47
|
+
schema_name = "#{filename}.#{Ree::SCHEMA}.json"
|
|
48
|
+
nodes[-1] = schema_name
|
|
49
|
+
nodes.join('/')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @param [String] schema_path Absolute or relative path of a package schema (bc/accounts/package/accounts/Package.json)
|
|
53
|
+
# @return [String] Absolute or relative path of a package entry file (ex. bc/accounts/schemas/accounts.rb)
|
|
54
|
+
def package_entry_path(schema_path)
|
|
55
|
+
dir = Pathname.new(schema_path).dirname.to_s
|
|
56
|
+
name = dir.split('/').last
|
|
57
|
+
File.join(dir, "#{Ree::PACKAGE}/#{name}.rb")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @param [Ree::Package] package Package schema
|
|
61
|
+
# @return [String] Absolute package entry path (ex. /data/project/bc/accounts/package/accounts.rb)
|
|
62
|
+
def abs_package_entry_path(package)
|
|
63
|
+
File.join(project_root_dir(package), package.entry_rpath)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @param [Ree::Package] package Package schema
|
|
67
|
+
# @return [String] Absolute package folder path (ex. /data/project/bc/accounts/package/accounts)
|
|
68
|
+
def abs_package_module_dir(package)
|
|
69
|
+
File.join(
|
|
70
|
+
project_root_dir(package), package.dir, Ree::PACKAGE, package.name.to_s
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @param [Ree::Package] package Package schema
|
|
75
|
+
# @return [String] Absolute package schema path
|
|
76
|
+
def abs_package_schema_path(package)
|
|
77
|
+
File.join(project_root_dir(package), package.schema_rpath)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @param [Ree::Package] package Package schema
|
|
81
|
+
# @return [String] Absolute package folder path (ex. /data/project/bc/accounts)
|
|
82
|
+
def abs_package_dir(package)
|
|
83
|
+
File.join(project_root_dir(package), package.dir)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @param [Ree::Package] package Package schema
|
|
87
|
+
# @param [String] absolute file path
|
|
88
|
+
# @return [String] File path relative to package (ex. accounts/entities/user.rb)
|
|
89
|
+
def package_relative_path(package, path)
|
|
90
|
+
Pathname
|
|
91
|
+
.new(path)
|
|
92
|
+
.relative_path_from(File.join(Ree.root_dir, package.dir, Ree::PACKAGE))
|
|
93
|
+
.to_s
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def project_root_dir(package)
|
|
97
|
+
if package.gem?
|
|
98
|
+
Ree.gem(package.gem_name).dir
|
|
99
|
+
else
|
|
100
|
+
Ree.root_dir
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal = true
|
|
2
|
+
|
|
3
|
+
class Ree::BuildPackageDsl
|
|
4
|
+
include Ree::Args
|
|
5
|
+
|
|
6
|
+
attr_reader :package
|
|
7
|
+
|
|
8
|
+
# @param [Ree::PackagesFacade] packages_facade
|
|
9
|
+
# @param [Module] mod
|
|
10
|
+
# @param [Nilor[String]] path
|
|
11
|
+
def initialize(packages_facade, mod)
|
|
12
|
+
@packages_facade = packages_facade
|
|
13
|
+
@package = register_package(mod)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @param [ArrayOf[String]] lists
|
|
17
|
+
def tags(list)
|
|
18
|
+
list.each do |tag|
|
|
19
|
+
check_arg(tag, :tag, String)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
list += [@package.name.to_s]
|
|
23
|
+
list.uniq
|
|
24
|
+
|
|
25
|
+
@package.set_tags(list)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @param [Symbol] depends_on
|
|
29
|
+
def depends_on(depends_on)
|
|
30
|
+
check_arg(depends_on, :depends_on, Symbol)
|
|
31
|
+
|
|
32
|
+
if depends_on == @package.name
|
|
33
|
+
raise_error("A package cannot depend on itself")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if @package.get_dep(depends_on)
|
|
37
|
+
raise_error("Dependent package :#{depends_on} already added for package :#{@package.name}")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
package_dep = @package.set_dep(
|
|
41
|
+
Ree::PackageDep.new(depends_on)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
dep_package = begin
|
|
45
|
+
@packages_facade.get_package(depends_on)
|
|
46
|
+
rescue Ree::Error
|
|
47
|
+
raise_error("Dependent package :#{depends_on} was not found in #{Ree::PACKAGES_SCHEMA_FILE}. Run `ree gen.packages_json` to update schema or fix package name")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
@packages_facade.load_package_entry(dep_package.name)
|
|
51
|
+
|
|
52
|
+
package_dep
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @param [Proc] block
|
|
56
|
+
def default_links(&block)
|
|
57
|
+
raise Ree::Error.new("block missing") if !block_given?
|
|
58
|
+
|
|
59
|
+
@package.set_default_links(&block)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @param [String] var_name
|
|
63
|
+
# @param [Nilor[String]] doc
|
|
64
|
+
def env_var(var_name, doc: nil)
|
|
65
|
+
check_arg(var_name, :env_var, String)
|
|
66
|
+
check_arg(doc, :doc, String) if doc
|
|
67
|
+
|
|
68
|
+
if @package.get_env_var(var_name)
|
|
69
|
+
raise_error("Duplicate env var '#{var_name}'")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
@package.set_env_var(
|
|
73
|
+
Ree::PackageEnvVar.new(
|
|
74
|
+
var_name, doc
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @param [HashOf[Symbol, ArrayOf[Symbol]]] opts
|
|
80
|
+
def preload(opts)
|
|
81
|
+
check_arg(opts, :opts, Hash)
|
|
82
|
+
|
|
83
|
+
opts.each do |env, list|
|
|
84
|
+
check_arg(list, :object_list, Array)
|
|
85
|
+
|
|
86
|
+
list.each do |object_name|
|
|
87
|
+
check_arg(object_name, :object_name, Symbol)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
@package.set_preload(opts)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def check_module(mod)
|
|
97
|
+
check_arg(mod, :module_name, Module)
|
|
98
|
+
module_name = mod.to_s
|
|
99
|
+
list = module_name.split('::')
|
|
100
|
+
|
|
101
|
+
if list.size != 1
|
|
102
|
+
raise Ree::Error.new("depends_on should be defined for top level modules only", :invalid_dsl_usage)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def register_package(mod)
|
|
107
|
+
check_module(mod)
|
|
108
|
+
check_arg(mod, :module, Module)
|
|
109
|
+
|
|
110
|
+
if mod.name.nil?
|
|
111
|
+
raise Ree::Error.new("package decorator should be applied to a named module", :invalid_dsl_usage)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
path = Object.const_source_location(mod.name)[0].split(':').first
|
|
115
|
+
module_name = mod.to_s
|
|
116
|
+
list = module_name.split('::')
|
|
117
|
+
|
|
118
|
+
if list.size != 1
|
|
119
|
+
raise Ree::Error.new("package should be defined for top level modules only", :invalid_dsl_usage)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
name_from_path = File.basename(path, ".*").to_sym
|
|
123
|
+
name = Ree::StringUtils.underscore(list[0]).to_sym
|
|
124
|
+
|
|
125
|
+
if !Ree.irb_mode? && name != name_from_path
|
|
126
|
+
raise Ree::Error.new("Package module '#{module_name}' does not correspond to package name 'name'. Fix file name or module name.")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
package = @packages_facade.get_package(name, false)
|
|
130
|
+
|
|
131
|
+
if package.nil?
|
|
132
|
+
package = Ree::Package.new(Ree::VERSION, name, nil, nil, nil)
|
|
133
|
+
@packages_facade.store_package(package)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
package.set_module(mod)
|
|
137
|
+
package.set_tags([name])
|
|
138
|
+
|
|
139
|
+
package.reset
|
|
140
|
+
package.set_entry_loaded
|
|
141
|
+
package.set_loaded
|
|
142
|
+
|
|
143
|
+
package
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def raise_error(text, code = :invalid_dsl_usage)
|
|
147
|
+
msg = <<~DOC
|
|
148
|
+
package: :#{@package.name}
|
|
149
|
+
path: #{File.join(Ree.root_dir, @package.entry_rpath)}
|
|
150
|
+
error: #{text}
|
|
151
|
+
DOC
|
|
152
|
+
|
|
153
|
+
raise Ree::Error.new(msg, code)
|
|
154
|
+
end
|
|
155
|
+
end
|