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.
Files changed (140) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +13 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +5 -0
  6. data/CODE_OF_CONDUCT.md +84 -0
  7. data/Gemfile +9 -0
  8. data/Gemfile.lock +41 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +474 -0
  11. data/Rakefile +8 -0
  12. data/bin/console +8 -0
  13. data/bin/setup +8 -0
  14. data/exe/ree +264 -0
  15. data/lib/ree/args.rb +34 -0
  16. data/lib/ree/bean_dsl.rb +24 -0
  17. data/lib/ree/cli/generate_package.rb +18 -0
  18. data/lib/ree/cli/generate_package_schema.rb +54 -0
  19. data/lib/ree/cli/generate_packages_schema.rb +17 -0
  20. data/lib/ree/cli/generate_template.rb +20 -0
  21. data/lib/ree/cli/init.rb +22 -0
  22. data/lib/ree/cli/spec_runner.rb +184 -0
  23. data/lib/ree/cli.rb +12 -0
  24. data/lib/ree/container.rb +67 -0
  25. data/lib/ree/contracts/arg_contracts/any.rb +15 -0
  26. data/lib/ree/contracts/arg_contracts/array_of.rb +52 -0
  27. data/lib/ree/contracts/arg_contracts/block.rb +15 -0
  28. data/lib/ree/contracts/arg_contracts/bool.rb +21 -0
  29. data/lib/ree/contracts/arg_contracts/eq.rb +28 -0
  30. data/lib/ree/contracts/arg_contracts/exactly.rb +28 -0
  31. data/lib/ree/contracts/arg_contracts/hash_of.rb +59 -0
  32. data/lib/ree/contracts/arg_contracts/ksplat.rb +141 -0
  33. data/lib/ree/contracts/arg_contracts/kwargs.rb +22 -0
  34. data/lib/ree/contracts/arg_contracts/nilor.rb +16 -0
  35. data/lib/ree/contracts/arg_contracts/none.rb +15 -0
  36. data/lib/ree/contracts/arg_contracts/optblock.rb +11 -0
  37. data/lib/ree/contracts/arg_contracts/or.rb +30 -0
  38. data/lib/ree/contracts/arg_contracts/range_of.rb +51 -0
  39. data/lib/ree/contracts/arg_contracts/set_of.rb +54 -0
  40. data/lib/ree/contracts/arg_contracts/splat.rb +297 -0
  41. data/lib/ree/contracts/arg_contracts/splat_of.rb +64 -0
  42. data/lib/ree/contracts/arg_contracts/squarable.rb +11 -0
  43. data/lib/ree/contracts/arg_contracts/subclass_of.rb +28 -0
  44. data/lib/ree/contracts/arg_contracts.rb +29 -0
  45. data/lib/ree/contracts/called_args_validator.rb +291 -0
  46. data/lib/ree/contracts/contract_definition.rb +142 -0
  47. data/lib/ree/contracts/contractable.rb +34 -0
  48. data/lib/ree/contracts/core.rb +17 -0
  49. data/lib/ree/contracts/engine.rb +71 -0
  50. data/lib/ree/contracts/engine_proxy.rb +13 -0
  51. data/lib/ree/contracts/errors/bad_contract_error.rb +4 -0
  52. data/lib/ree/contracts/errors/contract_error.rb +4 -0
  53. data/lib/ree/contracts/errors/error.rb +4 -0
  54. data/lib/ree/contracts/errors/return_contract_error.rb +4 -0
  55. data/lib/ree/contracts/method_decorator.rb +158 -0
  56. data/lib/ree/contracts/truncatable.rb +9 -0
  57. data/lib/ree/contracts/utils.rb +9 -0
  58. data/lib/ree/contracts/validators/array_validator.rb +51 -0
  59. data/lib/ree/contracts/validators/base_validator.rb +27 -0
  60. data/lib/ree/contracts/validators/class_validator.rb +17 -0
  61. data/lib/ree/contracts/validators/default_validator.rb +20 -0
  62. data/lib/ree/contracts/validators/hash_validator.rb +100 -0
  63. data/lib/ree/contracts/validators/proc_validator.rb +17 -0
  64. data/lib/ree/contracts/validators/range_validator.rb +17 -0
  65. data/lib/ree/contracts/validators/regexp_validator.rb +17 -0
  66. data/lib/ree/contracts/validators/valid_validator.rb +28 -0
  67. data/lib/ree/contracts/validators.rb +42 -0
  68. data/lib/ree/contracts.rb +45 -0
  69. data/lib/ree/core/link_validator.rb +42 -0
  70. data/lib/ree/core/object.rb +132 -0
  71. data/lib/ree/core/object_error.rb +9 -0
  72. data/lib/ree/core/object_link.rb +21 -0
  73. data/lib/ree/core/object_schema.rb +47 -0
  74. data/lib/ree/core/object_schema_builder.rb +110 -0
  75. data/lib/ree/core/package.rb +177 -0
  76. data/lib/ree/core/package_dep.rb +9 -0
  77. data/lib/ree/core/package_env_var.rb +12 -0
  78. data/lib/ree/core/package_loader.rb +95 -0
  79. data/lib/ree/core/package_schema.rb +27 -0
  80. data/lib/ree/core/package_schema_builder.rb +53 -0
  81. data/lib/ree/core/package_schema_loader.rb +170 -0
  82. data/lib/ree/core/packages_detector.rb +43 -0
  83. data/lib/ree/core/packages_schema.rb +19 -0
  84. data/lib/ree/core/packages_schema_builder.rb +50 -0
  85. data/lib/ree/core/packages_schema_loader.rb +95 -0
  86. data/lib/ree/core/packages_schema_locator.rb +27 -0
  87. data/lib/ree/core/packages_store.rb +32 -0
  88. data/lib/ree/core/path_helper.rb +104 -0
  89. data/lib/ree/dsl/build_package_dsl.rb +155 -0
  90. data/lib/ree/dsl/domain_error.rb +4 -0
  91. data/lib/ree/dsl/error_builder.rb +39 -0
  92. data/lib/ree/dsl/error_dsl.rb +27 -0
  93. data/lib/ree/dsl/import_dsl.rb +106 -0
  94. data/lib/ree/dsl/link_import_builder.rb +66 -0
  95. data/lib/ree/dsl/object_dsl.rb +319 -0
  96. data/lib/ree/dsl/object_hooks.rb +6 -0
  97. data/lib/ree/dsl/package_require.rb +44 -0
  98. data/lib/ree/error.rb +11 -0
  99. data/lib/ree/facades/packages_facade.rb +197 -0
  100. data/lib/ree/fn_dsl.rb +24 -0
  101. data/lib/ree/gen/init.rb +64 -0
  102. data/lib/ree/gen/package.rb +56 -0
  103. data/lib/ree/gen.rb +8 -0
  104. data/lib/ree/handlers/template_handler.rb +118 -0
  105. data/lib/ree/link_dsl.rb +175 -0
  106. data/lib/ree/object_compiler.rb +149 -0
  107. data/lib/ree/package_dsl.rb +34 -0
  108. data/lib/ree/rspec_link_dsl.rb +19 -0
  109. data/lib/ree/spec_runner/command_generator.rb +49 -0
  110. data/lib/ree/spec_runner/command_params.rb +9 -0
  111. data/lib/ree/spec_runner/runner.rb +200 -0
  112. data/lib/ree/spec_runner/spec_filename_matcher.rb +27 -0
  113. data/lib/ree/spec_runner/view.rb +30 -0
  114. data/lib/ree/spec_runner.rb +11 -0
  115. data/lib/ree/templates/init/.gitignore +1 -0
  116. data/lib/ree/templates/init/.irbrc +13 -0
  117. data/lib/ree/templates/init/.rspec +3 -0
  118. data/lib/ree/templates/init/.ruby-version +1 -0
  119. data/lib/ree/templates/init/Gemfile +7 -0
  120. data/lib/ree/templates/init/Packages.schema.json +1 -0
  121. data/lib/ree/templates/init/bin/console +5 -0
  122. data/lib/ree/templates/init/readme.md +2 -0
  123. data/lib/ree/templates/init/ree.setup.rb +21 -0
  124. data/lib/ree/templates/init/spec.init.rb +7 -0
  125. data/lib/ree/templates/package/.gitignore +0 -0
  126. data/lib/ree/templates/package/.rspec +2 -0
  127. data/lib/ree/templates/package/<%=package_subdir_name%>/<%=package_name%>/.gitkeep +0 -0
  128. data/lib/ree/templates/package/<%=package_subdir_name%>/<%=package_name%>.rb +15 -0
  129. data/lib/ree/templates/package/Package.schema.json +0 -0
  130. data/lib/ree/templates/package/bin/console +5 -0
  131. data/lib/ree/templates/package/spec/package_schema_spec.rb +14 -0
  132. data/lib/ree/templates/package/spec/spec_helper.rb +3 -0
  133. data/lib/ree/templates/template_detector.rb +35 -0
  134. data/lib/ree/templates/template_renderer.rb +55 -0
  135. data/lib/ree/utils/render_utils.rb +20 -0
  136. data/lib/ree/utils/string_utils.rb +29 -0
  137. data/lib/ree/version.rb +5 -0
  138. data/lib/ree.rb +279 -0
  139. data/sig/ree.rbs +4 -0
  140. 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
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::DomainError < StandardError
4
+ end