ree 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,132 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::Object
4
+ attr_reader :name, :rpath, :schema_rpath, :package_name, :klass,
5
+ :package_name, :factory, :after_init,
6
+ :class_name, :links, :mount_as, :freeze,
7
+ :errors, :linked_const_list, :compiled_frozen,
8
+ :singleton
9
+
10
+ # @param [Symbol] name Object name
11
+ # @param [String] schema_rpath Object schema path relative to project root dir
12
+ # @param [String] rpath Object source file path relative to project root dir
13
+ def initialize(name, schema_rpath, rpath)
14
+ @name = name
15
+ @schema_rpath = schema_rpath
16
+ @rpath = rpath
17
+ @links = []
18
+ @errors = []
19
+ @loaded = false
20
+ @freeze = true
21
+ @compiled = false
22
+ @singleton = false
23
+ @compiled_frozen = @freeze
24
+ @linked_const_list = []
25
+ end
26
+
27
+ def reset
28
+ @compiled = false
29
+ @singleton = false
30
+ @loaded = false
31
+ @factory = nil
32
+ @after_init = nil
33
+ @freeze = true
34
+ @links = []
35
+ @errors = []
36
+ @linked_const_list = []
37
+ end
38
+
39
+ # @param [ArrayOf[String]] list List of imported constants, modules and classes
40
+ # @return [ArrayOf[String]] All imported constants
41
+ def add_const_list(list)
42
+ @linked_const_list += list
43
+ @linked_const_list.uniq
44
+ end
45
+
46
+ # @param [Bool]
47
+ def set_as_compiled(frozen)
48
+ @compiled = true
49
+ @compiled_frozen = frozen
50
+ end
51
+
52
+ def set_as_not_compiled
53
+ @compiled = false
54
+ @compiled_frozen = @freeze
55
+ end
56
+
57
+ def compiled?
58
+ @compiled
59
+ end
60
+
61
+ def factory?
62
+ !!@factory
63
+ end
64
+
65
+ def after_init?
66
+ !!@after_init
67
+ end
68
+
69
+ def set_loaded
70
+ @loaded = true
71
+ end
72
+
73
+ def loaded?
74
+ @loaded
75
+ end
76
+
77
+ def freeze?
78
+ @freeze
79
+ end
80
+
81
+ # @param [Symbol] val Object mount as type (:fn or :bean)
82
+ def set_mount_as(val)
83
+ @mount_as = val; self
84
+ end
85
+
86
+ # @param [Bool]
87
+ def set_freeze(val)
88
+ @freeze = val; self
89
+ end
90
+
91
+ def set_as_singleton
92
+ @singleton = true; self
93
+ end
94
+
95
+ def object?
96
+ @mount_as == :object
97
+ end
98
+
99
+ def fn?
100
+ @mount_as == :fn
101
+ end
102
+
103
+ # @param [String] rpath Object source file path relative to project root dir
104
+ def set_rpath(val)
105
+ @rpath = val; self
106
+ end
107
+
108
+ # @param [String] schema_rpath Object schema path relative to project root dir
109
+ def set_schema_rpath(val)
110
+ @schema_rpath = val; self
111
+ end
112
+
113
+ # @param [Class] Object class
114
+ def set_class(klass)
115
+ @klass = klass; @class_name = klass.to_s; self
116
+ end
117
+
118
+ # @param [Symbol] Package name
119
+ def set_package(val)
120
+ @package_name = val; self
121
+ end
122
+
123
+ # @param [Symbol] Factory method name
124
+ def set_factory(val)
125
+ @factory = val; self
126
+ end
127
+
128
+ # @param [Symbol] After init method name
129
+ def set_after_init(val)
130
+ @after_init = val; self
131
+ end
132
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::ObjectError
4
+ attr_reader :class_name
5
+
6
+ def initialize(class_name)
7
+ @class_name = class_name
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::ObjectLink
4
+ attr_reader :object_name, :package_name, :as, :constants
5
+
6
+ # @param [Symbol] object_name Linked object name
7
+ # @param [Symbol] package_name Linked object package
8
+ # @param [Symbol] as Linked object alias name
9
+ def initialize(object_name, package_name, as)
10
+ @object_name = object_name
11
+ @package_name = package_name
12
+ @as = as
13
+ @constants = []
14
+ end
15
+
16
+ # @param [ArrayOf[String]]
17
+ # @return [ArrayOf[String]]
18
+ def set_constants(const_list)
19
+ @constants = const_list
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal = true
2
+
3
+ module Ree::ObjectSchema
4
+ SCHEMA_TYPE = 'schema_type'
5
+ REE_VERSION = 'ree_version'
6
+ NAME = 'name'
7
+ OBJECT = 'object'
8
+ LINKS = 'links'
9
+ CONTEXT = 'context'
10
+ PATH = 'path'
11
+ METHODS = 'methods'
12
+ CLASS = 'class'
13
+ PACKAGE_NAME = 'package_name'
14
+ MOUNT_AS = 'mount_as'
15
+ FACTORY = 'factory'
16
+ ERRORS = 'errors'
17
+
18
+ module Links
19
+ NAME = 'name'
20
+ PACKAGE_NAME = 'package_name'
21
+ TARGET = 'target'
22
+ AS = 'as'
23
+ IMPORTS = 'imports'
24
+
25
+ module Imports
26
+ CONST = 'const'
27
+ AS = 'as'
28
+ end
29
+ end
30
+
31
+ module Methods
32
+ ARGS = 'args'
33
+ METHOD = 'method'
34
+ RETURN = 'return'
35
+ THROWS = 'throws'
36
+ DOC = 'doc'
37
+
38
+ module Args
39
+ ARG = 'arg'
40
+ TYPE = 'type'
41
+ end
42
+ end
43
+
44
+ module Errors
45
+ CODE = 'code'
46
+ end
47
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::ObjectSchemaBuilder
4
+ Schema = Ree::ObjectSchema
5
+
6
+ # @param [Ree::Object] object
7
+ # @param [String] - path to object.schema.json file (ex. /project/bc/accounts/schemas/accounts/accounts_cfg.schema.json)
8
+ # @return [String]
9
+ def call(object, schema_path)
10
+ Ree.logger.debug("generating object schema for '#{object.name}' package")
11
+
12
+ if !File.exists?(schema_path)
13
+ only_dir_path = schema_path.split('/')[0..-2]
14
+ FileUtils.mkdir_p(File.join(only_dir_path))
15
+ end
16
+
17
+ if !object.loaded?
18
+ raise Ree::Error.new("object `#{object.name}` from package `#{object.package_name}` is not loaded", :invalid_schema)
19
+ end
20
+
21
+ data = {
22
+ Schema::SCHEMA_TYPE => Schema::OBJECT,
23
+ Schema::REE_VERSION => Ree::VERSION,
24
+ Schema::NAME => object.name,
25
+ Schema::PATH => object.rpath,
26
+ Schema::MOUNT_AS => object.mount_as,
27
+ Schema::CLASS => object.klass.name,
28
+ Schema::FACTORY => object.factory,
29
+ Schema::METHODS => map_object_methods(object),
30
+ Schema::LINKS => object.links.sort_by(&:object_name).map { |link|
31
+ {
32
+ Schema::Links::TARGET => link.object_name,
33
+ Schema::Links::PACKAGE_NAME => link.package_name,
34
+ Schema::Links::AS => link.as,
35
+ Schema::Links::IMPORTS => link.constants
36
+ }
37
+ }
38
+ }
39
+
40
+ json = JSON.pretty_generate(data)
41
+
42
+ File.write(schema_path, json, mode: 'w')
43
+ json
44
+ end
45
+
46
+ private
47
+
48
+ Arg = Ree::Contracts::CalledArgsValidator::Arg
49
+
50
+ def map_object_methods(object)
51
+ if !object.fn?
52
+ return []
53
+ end
54
+
55
+ klass = object.klass
56
+
57
+ method_decorator = Ree::Contracts.get_method_decorator(
58
+ klass, :call, scope: :instance
59
+ )
60
+
61
+ begin
62
+ if method_decorator.nil?
63
+ parameters = klass.instance_method(:call).parameters
64
+
65
+ args = parameters.inject({}) do |res, param|
66
+ res[param.last] = Arg.new(
67
+ param.last, param.first, nil, nil
68
+ )
69
+
70
+ res
71
+ end
72
+ else
73
+ parameters = method_decorator.args.params
74
+ args = method_decorator.args.get_args
75
+ end
76
+ rescue NameError
77
+ raise Ree::Error.new("method call is not defined for #{klass}")
78
+ end
79
+
80
+ arg_list = parameters.map do |param|
81
+ arg = args[param.last]
82
+ validator = arg.validator
83
+ arg_type = arg.type
84
+
85
+ type = if validator
86
+ validator.to_s
87
+ else
88
+ if arg_type == :block
89
+ "Block"
90
+ else
91
+ "Any"
92
+ end
93
+ end
94
+
95
+ {
96
+ Schema::Methods::Args::ARG => arg.name,
97
+ Schema::Methods::Args::TYPE => type
98
+ }
99
+ end
100
+
101
+ [
102
+ {
103
+ Schema::Methods::DOC => method_decorator&.doc || "",
104
+ Schema::Methods::THROWS => method_decorator&.errors&.map { _1.name } || [],
105
+ Schema::Methods::RETURN => method_decorator&.contract_definition&.return_contract || "Any",
106
+ Schema::Methods::ARGS => arg_list
107
+ }
108
+ ]
109
+ end
110
+ end
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal = true
2
+
3
+ require 'pathname'
4
+
5
+ class Ree::Package
6
+ attr_reader :ree_version, :name, :schema_rpath, :entry_rpath,
7
+ :module, :tags, :preload, :default_links, :gem_name
8
+
9
+ def initialize(ree_version, name, entry_rpath, schema_rpath, gem_name = nil)
10
+ @ree_version = ree_version
11
+ @name = name
12
+ @schema_rpath = schema_rpath
13
+ @entry_rpath = entry_rpath
14
+ @objects_store = {}
15
+ @deps_store = {}
16
+ @env_vars_store = {}
17
+ @entry_loaded = false
18
+ @schema_loaded = false
19
+ @loaded = false
20
+ @tags = []
21
+ @preload = {}
22
+ @preloaded = false
23
+ @gem_name = gem_name
24
+ end
25
+
26
+ def set_default_links(&block)
27
+ @default_links = block; self
28
+ end
29
+
30
+ # @param [Bool] val
31
+ def set_preloaded(val)
32
+ @preloaded = val; self
33
+ end
34
+
35
+ def preloaded?
36
+ @preloaded
37
+ end
38
+
39
+ # @param [String] val
40
+ def set_ree_version(val)
41
+ @ree_version = val; self
42
+ end
43
+
44
+ # @param [String] val
45
+ def set_entry_rpath(val)
46
+ @entry_rpath = val; self
47
+ end
48
+
49
+ # @param [ArrayOf[String]] list
50
+ def set_tags(list)
51
+ @tags = (@tags + list).map(&:to_s).uniq; self
52
+ end
53
+
54
+ # @param [String] val
55
+ def set_schema_rpath(val)
56
+ @schema_rpath = val; self
57
+ end
58
+
59
+ def reset
60
+ @entry_loaded = false
61
+ @schema_loaded = false
62
+ @loaded = false
63
+ @deps_store = {}
64
+ @env_vars_store = {}
65
+ @preload = {}
66
+ end
67
+
68
+ def set_preload(val)
69
+ @preload = val; self
70
+ end
71
+
72
+ def loaded?
73
+ @loaded
74
+ end
75
+
76
+ def set_loaded
77
+ @loaded = true
78
+ end
79
+
80
+ def set_entry_loaded
81
+ @entry_loaded = true
82
+ end
83
+
84
+ def set_schema_loaded
85
+ @schema_loaded = true
86
+ end
87
+
88
+ def entry_loaded?
89
+ @entry_loaded
90
+ end
91
+
92
+ def schema_loaded?
93
+ @schema_loaded
94
+ end
95
+
96
+ def dir
97
+ @dir ||= @schema_rpath ? Pathname.new(@schema_rpath).dirname.to_s : nil
98
+ end
99
+
100
+ def gem?
101
+ !!@gem_name
102
+ end
103
+
104
+ # @param [Module] mod
105
+ def set_module(mod)
106
+ @module = mod; self
107
+ end
108
+
109
+ # @list [ArrayOf[Ree::PackageDepsSchema]]
110
+ def set_deps(list)
111
+ list.each do |item|
112
+ @deps_store[item.name] = item
113
+ end
114
+ end
115
+
116
+ def deps
117
+ @deps_store.values
118
+ end
119
+
120
+ # @param [Ree::PackageDep] dep
121
+ def set_dep(dep)
122
+ old = @deps_store[dep.name]
123
+ @deps_store[dep.name] = dep
124
+ old
125
+ end
126
+
127
+ # @param [Symbol] name
128
+ def get_dep(name)
129
+ @deps_store[name]
130
+ end
131
+
132
+ # @param [ArrayOf[Ree::PackageEnvVar]] list
133
+ def set_env_vars(list)
134
+ list.each do |item|
135
+ @env_vars_store[item.name] = item
136
+ end
137
+ end
138
+
139
+ def env_vars
140
+ @env_vars_store.values
141
+ end
142
+
143
+ # @param [Ree::PackageEnvVar] var
144
+ def set_env_var(var)
145
+ old = @env_vars_store[var.name]
146
+ @env_vars_store[var.name] = var
147
+ old
148
+ end
149
+
150
+ # @param [String] name
151
+ def get_env_var(name)
152
+ @env_vars_store[name]
153
+ end
154
+
155
+ # @param [Ree::Object] object
156
+ # @return [Nilor[Ree::Object]] Previous object version
157
+ def set_object(object)
158
+ if object.package_name != @name
159
+ raise Ree::Error.new("package should only include objects from the same package")
160
+ end
161
+
162
+ existing = @objects_store[object.name]
163
+ return existing if existing
164
+
165
+ @objects_store[object.name] = object
166
+ end
167
+
168
+ # @param [Symbol] name
169
+ # @return [Nilor[Ree::Object]]
170
+ def get_object(name)
171
+ @objects_store[name]
172
+ end
173
+
174
+ def objects
175
+ @objects_store.values.flatten
176
+ end
177
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::PackageDep
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::PackageEnvVar
4
+ attr_reader :name, :doc
5
+
6
+ # @param [String] name Env var name
7
+ # @param [Nilor[String]] Env var description
8
+ def initialize(name, doc)
9
+ @name = name
10
+ @doc = doc
11
+ end
12
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal = true
2
+
3
+ require 'set'
4
+ require 'pathname'
5
+
6
+ class Ree::PackageLoader
7
+ def initialize(packages_store)
8
+ @packages_store = packages_store
9
+ @loaded_paths = {}
10
+ @loaded_packages = {}
11
+ end
12
+
13
+ def reset
14
+ @loaded_paths = {}
15
+ end
16
+
17
+ # @param [Symbol] name Package name
18
+ def call(name)
19
+ return @loaded_packages[name] if @loaded_packages.has_key?(name)
20
+
21
+ Ree.logger.debug("full_package_load(:#{name})")
22
+ recursively_load_package(name, Hash.new(false))
23
+ @loaded_packages[name]
24
+ end
25
+
26
+ def load_file(path, package_name)
27
+ @loaded_paths[package_name] ||= {}
28
+ return if @loaded_paths[package_name][path]
29
+ @loaded_paths[package_name][path] = true
30
+
31
+ Ree.logger.debug("load_file(:#{package_name}, '#{path}')")
32
+ Kernel.require(path)
33
+ end
34
+
35
+ private
36
+
37
+ def recursively_load_package(name, loaded_packages)
38
+ @loaded_packages[name] = true
39
+ package = @packages_store.get(name)
40
+
41
+ if package.dir.nil?
42
+ package.set_schema_loaded
43
+ return package
44
+ end
45
+
46
+ if !package
47
+ raise Ree::Error.new(
48
+ "Package :#{name} was not found. Did you mistype the name? Run `ree gen.packages_json` to update Packages.schema.json",
49
+ :invalid_package_name
50
+ )
51
+ end
52
+
53
+ not_loaded = Set.new(
54
+ [name, package.deps.map(&:name)]
55
+ .uniq
56
+ .select { |pn| !loaded_packages[pn] }
57
+ )
58
+
59
+ if not_loaded.include?(name)
60
+ load_file(
61
+ Ree::PathHelper.abs_package_entry_path(package), name
62
+ )
63
+
64
+ Dir[File.join(Ree::PathHelper.abs_package_module_dir(package), '**/*.rb')].each do |path|
65
+ load_file(path, name)
66
+ end
67
+
68
+ loaded_packages[name] = true
69
+ end
70
+
71
+ if !ENV.has_key?('REE_SKIP_ENV_VARS_CHECK')
72
+ package.env_vars.each do |env_var|
73
+ if !ENV.has_key?(env_var.name)
74
+ msg = <<~DOC
75
+ package: :#{package.name}
76
+ path: #{File.join(Ree::PathHelper.project_root_dir(package), package.entry_rpath)}
77
+ error: Package :#{name} requires env var '#{env_var.name}' to be set
78
+ DOC
79
+
80
+ raise Ree::Error.new(msg, :env_var_not_set)
81
+ end
82
+ end
83
+ end
84
+
85
+ package.deps.each do |dep|
86
+ if !loaded_packages[dep.name]
87
+ recursively_load_package(dep.name, loaded_packages)
88
+ end
89
+ end
90
+
91
+ package.set_schema_loaded
92
+
93
+ @loaded_packages[name] = package
94
+ end
95
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal = true
2
+
3
+ module Ree::PackageSchema
4
+ SCHEMA_TYPE = 'schema_type'
5
+ REE_VERSION = 'ree_version'
6
+ NAME = 'name'
7
+ PACKAGE = 'package'
8
+ ENTRY_PATH = 'entry_path'
9
+ OBJECTS = 'objects'
10
+ ENV_VARS = 'env_vars'
11
+ DEPENDS_ON = 'depends_on'
12
+ TAGS = 'tags'
13
+
14
+ module Objects
15
+ NAME = 'name'
16
+ SCHEMA = 'schema'
17
+ end
18
+
19
+ module DependsOn
20
+ NAME = 'name'
21
+ end
22
+
23
+ module EnvVars
24
+ NAME = 'name'
25
+ DOC = 'doc'
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal = true
2
+
3
+ require 'pathname'
4
+ require 'json'
5
+
6
+ class Ree::PackageSchemaBuilder
7
+ Schema = Ree::PackageSchema
8
+
9
+ # @param [Ree::Package] package
10
+ # @param [String] - abs_path Absolute path to Package.schema.json file (ex. /project/bc/accounts/Package.schema.json)
11
+ # @return [nil]
12
+ def call(package, abs_path)
13
+ Ree.logger.debug("generating package schema for '#{package.name}' package")
14
+
15
+ if !File.exists?(abs_path)
16
+ raise Ree::Error.new("File does not exist: #{abs_path}", :invalid_path)
17
+ end
18
+
19
+ if !package.loaded?
20
+ raise Ree::Error.new("package schema should be loaded", :invalid_schema)
21
+ end
22
+
23
+ data = {
24
+ Schema::SCHEMA_TYPE => Schema::PACKAGE,
25
+ Schema::REE_VERSION => Ree::VERSION,
26
+ Schema::NAME => package.name,
27
+ Schema::ENTRY_PATH => package.entry_rpath,
28
+ Schema::TAGS => package.tags,
29
+ Schema::DEPENDS_ON => package.deps.sort_by(&:name).map { |dep|
30
+ {
31
+ Schema::DependsOn::NAME => dep.name,
32
+ }
33
+ },
34
+ Schema::ENV_VARS => package.env_vars.sort_by(&:name).map { |var|
35
+ {
36
+ Schema::EnvVars::NAME => var.name,
37
+ Schema::EnvVars::DOC => var.doc,
38
+ }
39
+ },
40
+ Schema::OBJECTS => package.objects.select { !_1.rpath.nil? }.sort_by(&:name).map { |object|
41
+ {
42
+ Schema::Objects::NAME => object.name,
43
+ Schema::Objects::SCHEMA => object.schema_rpath,
44
+ }
45
+ }
46
+ }
47
+
48
+ json = JSON.pretty_generate(data)
49
+
50
+ File.write(abs_path, json, mode: 'w')
51
+ nil
52
+ end
53
+ end