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,197 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::PackagesFacade
4
+ include Ree::Args
5
+
6
+ attr_reader :packages_store, :package_loader
7
+
8
+ def initialize
9
+ load_packages_schema
10
+ @package_loader = Ree::PackageLoader.new(@packages_store)
11
+ end
12
+
13
+ class << self
14
+ def write_packages_schema
15
+ Ree.logger.debug("write_packages_schema")
16
+ Ree::PackagesSchemaBuilder.new.call
17
+ end
18
+ end
19
+
20
+ def perf_mode?(package)
21
+ package.gem? ? true : Ree.performance_mode?
22
+ end
23
+
24
+ # @param [Symbol] package_name
25
+ # @return [Ree::Package]
26
+ def get_loaded_package(package_name)
27
+ package = get_package(package_name)
28
+ return package if package.schema_loaded?
29
+
30
+ if perf_mode?(package)
31
+ read_package_schema_json(package_name)
32
+ else
33
+ load_entire_package(package_name)
34
+ end
35
+
36
+ package
37
+ end
38
+
39
+ # @param [Symbol] package_name
40
+ # @param [Symbol] object_name
41
+ # @return [Ree::Object]
42
+ def get_object(package_name, object_name)
43
+ package = get_loaded_package(package_name)
44
+ object = package.get_object(object_name)
45
+
46
+ if !object && perf_mode?(package)
47
+ raise Ree::Error.new("Ree object :#{object_name} for package :#{package_name} not found")
48
+ end
49
+
50
+ object
51
+ end
52
+
53
+ # @param [Symbol] package_name
54
+ # @return nil
55
+ def write_package_schema(package_name)
56
+ Ree.logger.debug("write_package_schema(:#{package_name})")
57
+
58
+ load_entire_package(package_name)
59
+ package = get_package(package_name)
60
+
61
+ if package.dir
62
+ schema_path = Ree::PathHelper.abs_package_schema_path(package)
63
+ Ree::PackageSchemaBuilder.new.call(package, schema_path)
64
+ end
65
+ end
66
+
67
+ # @param [Symbol] package_name
68
+ # @param [Symbol] object_name
69
+ # @return [String]
70
+ def write_object_schema(package_name, object_name)
71
+ Ree.logger.debug("write_object_schema(package_name: #{package_name}, object_name: #{object_name})")
72
+ object = get_object(package_name, object_name)
73
+
74
+ if !object || (object && !object&.schema_rpath)
75
+ raise Ree::Error.new("Object :#{object_name} schema path not found")
76
+ end
77
+
78
+ schema_path = Ree::PathHelper.abs_object_schema_path(object)
79
+
80
+ Ree::ObjectSchemaBuilder.new.call(object, schema_path)
81
+ end
82
+
83
+ # @param [Symbol] package_name
84
+ # @return nil
85
+ def load_package_entry(package_name)
86
+ package = @packages_store.get(package_name)
87
+ return if package.loaded?
88
+
89
+ Ree.logger.debug("load_package_entry(:#{package_name})")
90
+
91
+ load_file(
92
+ Ree::PathHelper.abs_package_entry_path(package),
93
+ package_name
94
+ )
95
+ end
96
+
97
+ # @param [Symbol] package_name
98
+ # @param [Symbol] object_name
99
+ # @return [Ree::Object]
100
+ def load_package_object(package_name, object_name)
101
+ package = get_loaded_package(package_name)
102
+ load_package_entry(package_name)
103
+
104
+ object = get_object(package_name, object_name)
105
+ return object if object && object.loaded?
106
+
107
+ if !object && !perf_mode?(package)
108
+ Dir[
109
+ File.join(
110
+ Ree::PathHelper.abs_package_module_dir(package),
111
+ "**/#{object_name}.rb"
112
+ )
113
+ ].each do |path|
114
+ load_file(path, package_name)
115
+ end
116
+
117
+ object = get_object(package_name, object_name)
118
+ end
119
+
120
+ if !object
121
+ raise Ree::Error.new("object :#{object_name} from :#{package_name} was not found")
122
+ end
123
+
124
+ Ree.logger.debug("load_package_object(:#{package_name}, :#{object_name})")
125
+
126
+ if object.rpath
127
+ object_path = Ree::PathHelper.abs_object_path(object)
128
+ load_file(object_path, package_name)
129
+ end
130
+
131
+ object
132
+ end
133
+
134
+ # @param [Symbol] package_name
135
+ # @return [Ree::Package]
136
+ def load_entire_package(package_name)
137
+ @package_loader.call(package_name)
138
+ end
139
+
140
+ # @param [Symbol] package_name
141
+ # @return [Ree::Package]
142
+ def read_package_schema_json(package_name)
143
+ @loaded_schemas ||= {}
144
+ return @loaded_schemas[package_name] if @loaded_schemas[package_name]
145
+
146
+ Ree.logger.debug("read_package_schema_json(:#{package_name})")
147
+ package = get_package(package_name)
148
+
149
+ if !package.dir
150
+ package.set_schema_loaded
151
+ return package
152
+ end
153
+
154
+ schema_path = Ree::PathHelper.abs_package_schema_path(package)
155
+ @loaded_schemas[package_name] = Ree::PackageSchemaLoader.new.call(schema_path, package)
156
+ end
157
+
158
+ # @return [Ree::PackagesStore]
159
+ def load_packages_schema
160
+ Ree.logger.debug("load_packages_schema: #{self.object_id}")
161
+ @packages_store = Ree::PackagesSchemaLoader.new.call(Ree.packages_schema_path, @packages_store)
162
+
163
+ Ree.gems.each do |gem|
164
+ Ree::PackagesSchemaLoader.new.call(
165
+ gem.packages_schema_path, @packages_store, gem.name
166
+ )
167
+ end
168
+
169
+ @packages_store
170
+ end
171
+
172
+ # @param [Symbol] package_name
173
+ # @return [Ree::Package]
174
+ def get_package(package_name, raise_if_missing = true)
175
+ check_arg(package_name, :package_name, Symbol)
176
+ package = @packages_store.get(package_name)
177
+
178
+ if !package && raise_if_missing
179
+ raise Ree::Error.new("Package :#{package_name} is not found in Packages.schema.json. Run `ree gen.packages_json` to update schema.", :package_schema_not_found)
180
+ end
181
+
182
+ package
183
+ end
184
+
185
+ # @param [Ree::Package] package
186
+ # @return [Ree::Package]
187
+ def store_package(package)
188
+ @packages_store.add_package(package)
189
+ end
190
+
191
+ # @param [String] path
192
+ # @param [Symbol] package_name
193
+ # @return [nil]
194
+ def load_file(path, package_name)
195
+ @package_loader.load_file(path, package_name)
196
+ end
197
+ end
data/lib/ree/fn_dsl.rb ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::FnDSL
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ def self.extended(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def fn(name, &proc)
14
+ dsl = Ree::ObjectDsl.new(
15
+ Ree.container.packages_facade, name, self, :fn
16
+ )
17
+
18
+ dsl.instance_exec(&proc) if block_given?
19
+ dsl.object.set_as_compiled(false)
20
+
21
+ Ree.container.compile(dsl.package, name)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal = true
2
+
3
+ require 'fileutils'
4
+ require 'pathname'
5
+
6
+ module Ree
7
+ module Gen
8
+ class Init
9
+ TEMPLATE_NAME = 'init'
10
+ INIT_PATH = './'
11
+ LOCAL_TEMPLATES_PATH = '.ree/templates'
12
+
13
+ class << self
14
+ def generate(project_path:, test: 'rspec', console: 'irb', stdout: STDOUT)
15
+ Ree::Gen::Init.new(project_path, test, console, stdout).generate
16
+ end
17
+ end
18
+
19
+ def initialize(project_path, test, console, stdout)
20
+ @project_path = project_path
21
+ @test = test
22
+ @console = console
23
+ @template_detector = Ree::TemplateDetector.new(project_path)
24
+ @stdout = stdout
25
+ end
26
+
27
+ def generate
28
+ if @project_path.nil? || @project_path.empty?
29
+ raise Ree::Error.new("Project folder not specified. Type path to ree project, ex: 'ree init .'")
30
+ end
31
+
32
+ if !Dir.exist?(@project_path)
33
+ raise Ree::Error.new("#{@project_path} doesn't exist. Initialize new ree project with existing directory")
34
+ end
35
+
36
+ if File.exist?(File.join(@project_path, Ree::PACKAGES_SCHEMA_FILE))
37
+ raise Ree::Error.new("#{@project_path} has already #{Ree::PACKAGES_SCHEMA_FILE}")
38
+ end
39
+
40
+ generated_files = Ree::TemplateHandler.generate(
41
+ template_name: TEMPLATE_NAME,
42
+ project_path: @project_path,
43
+ local_path: INIT_PATH,
44
+ stdout: @stdout
45
+ )
46
+
47
+ FileUtils.mkdir_p(local_templates_path)
48
+
49
+ FileUtils.cp_r(
50
+ @template_detector.gem_template_folder('package'),
51
+ File.dirname(@template_detector.project_template_folder('package'))
52
+ )
53
+
54
+ generated_files
55
+ end
56
+
57
+ private
58
+
59
+ def local_templates_path
60
+ File.join(@project_path, LOCAL_TEMPLATES_PATH)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal = true
2
+
3
+ require 'fileutils'
4
+ require 'pathname'
5
+
6
+ module Ree
7
+ module Gen
8
+ class Package
9
+ TEMPLATE_NAME = 'package'
10
+
11
+ class << self
12
+ def generate(package_name:, project_path:, local_path:, locals: {})
13
+ Ree::Gen::Package.new(package_name, project_path, local_path, locals).create
14
+ end
15
+ end
16
+
17
+ def initialize(package_name, project_path, local_path, locals = {})
18
+ @project_path = project_path
19
+ @package_name = package_name
20
+ @local_path = local_path
21
+ @locals = locals
22
+ @schema = get_schema
23
+ end
24
+
25
+ def create
26
+ if Dir.exist?(File.join(Ree.root_dir, @local_path))
27
+ raise Ree::Error.new("Package directory #{@local_path} already exists")
28
+ end
29
+
30
+ if @package_name.nil? || @package_name.empty?
31
+ raise Ree::Error.new('Package name was not specified')
32
+ end
33
+
34
+ if @schema.packages.map(&:name).include?(@package_name)
35
+ raise Ree::Error.new('Package already exists')
36
+ end
37
+
38
+ generated_files = Ree::TemplateHandler.generate(
39
+ template_name: TEMPLATE_NAME,
40
+ project_path: @project_path,
41
+ local_path: @local_path,
42
+ locals: { package_name: @package_name, local_path: @local_path }.merge(@locals)
43
+ )
44
+
45
+ generated_files
46
+ end
47
+
48
+ def get_schema
49
+ @schema ||= begin
50
+ Ree.init(@project_path)
51
+ Ree.container.packages_facade.load_packages_schema
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
data/lib/ree/gen.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal = true
2
+
3
+ module Ree
4
+ module Gen
5
+ autoload :Init, 'ree/gen/init'
6
+ autoload :Package, 'ree/gen/package'
7
+ end
8
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal = true
2
+
3
+ require 'pathname'
4
+ require 'fileutils'
5
+
6
+ class Ree::TemplateHandler
7
+ REJECTED_TEMPLATE_FILES = %W(.DS_Store)
8
+ NOT_HANDLED_TEMPLATES_EXT = %W(.erb)
9
+
10
+ class << self
11
+ def generate(template_name:, local_path:, project_path:, locals: {},
12
+ stdout: STDOUT, stdin: STDIN)
13
+
14
+ Ree::TemplateHandler.new(
15
+ template_name: template_name.to_s,
16
+ local_path: local_path,
17
+ project_path: project_path,
18
+ locals: locals,
19
+ stdout: stdout,
20
+ stdin: stdin
21
+ ).generate
22
+ end
23
+ end
24
+
25
+ def initialize(
26
+ template_name:,
27
+ local_path:,
28
+ project_path:,
29
+ locals:,
30
+ stdout:,
31
+ stdin:
32
+ )
33
+
34
+ @template_name = template_name
35
+ @local_path = local_path
36
+ @project_path = project_path
37
+ @missing_variables = []
38
+ @stdout = stdout
39
+ @stdin = stdin
40
+ default_locals = { package_subdir_name: 'package' }
41
+ @locals = default_locals.merge(locals)
42
+ end
43
+
44
+ def generate
45
+ project_path = @project_path
46
+ template_detector = Ree::TemplateDetector.new(project_path)
47
+
48
+ @template_directory = template_detector.detect_template_folder(@template_name)
49
+ @destination_directory = File.join(project_path, @local_path)
50
+
51
+ template_files_list = Dir
52
+ .glob(File.join(@template_directory, '**', '*'), File::FNM_DOTMATCH)
53
+ .reject { |path| REJECTED_TEMPLATE_FILES.include? File.basename(path) }
54
+
55
+ template_files_list.each do |path|
56
+ @missing_variables.concat(
57
+ Ree::TemplateRenderer.get_undefined_variables(get_destination_path(path), @locals)
58
+ )
59
+
60
+ if handle_file_content?(path)
61
+ @missing_variables.concat(
62
+ Ree::TemplateRenderer.get_undefined_variables(File.read(path), @locals)
63
+ )
64
+ end
65
+ end
66
+
67
+ if @missing_variables.any?
68
+ @missing_variables.uniq!
69
+
70
+ @stdout.puts "Undefined variables were found:"
71
+ @missing_variables.size.times { |t| @stdout.puts " #{t+1}. #{@missing_variables[t]}" }
72
+
73
+ @missing_variables.each do |var|
74
+ @stdout.print "Type value for '#{var}': "
75
+ @locals[var] = @stdin.gets.chomp
76
+ end
77
+ end
78
+
79
+ template_files_list.map! do |path|
80
+ rendered_abs_path = Ree::TemplateRenderer.handle(get_destination_path(path), @locals)
81
+ rendered_rel_path = Pathname.new(rendered_abs_path).relative_path_from Pathname.new(project_path)
82
+
83
+ if File.file?(rendered_abs_path) && File.exists?(rendered_abs_path)
84
+ @stdout.puts "Warning! #{rendered_rel_path} already exists. Skipping file creation..."
85
+ next
86
+ end
87
+
88
+ if File.directory?(path)
89
+ FileUtils.mkdir_p(rendered_abs_path)
90
+ next
91
+ end
92
+
93
+ rendered_file_content = handle_file_content?(path) ?
94
+ Ree::TemplateRenderer.handle(File.read(path), @locals) :
95
+ File.read(path)
96
+
97
+ FileUtils.mkdir_p(File.dirname(rendered_abs_path))
98
+ File.open(rendered_abs_path, 'w') { |f| f.write rendered_file_content }
99
+
100
+ rendered_rel_path
101
+ end
102
+
103
+ template_files_list.compact
104
+ end
105
+
106
+ private
107
+
108
+ def get_destination_path(file)
109
+ return nil unless defined? @template_directory && defined? @destination_directory
110
+
111
+ template_rel_path = Pathname.new(file).relative_path_from Pathname.new(@template_directory)
112
+ File.join(@destination_directory, template_rel_path)
113
+ end
114
+
115
+ def handle_file_content?(path)
116
+ File.file?(path) && !NOT_HANDLED_TEMPLATES_EXT.include?(File.extname(path))
117
+ end
118
+ end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::LinkDSL
4
+ def self.included(base)
5
+ validate(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ def self.extended(base)
10
+ validate(base)
11
+ base.extend(ClassMethods)
12
+ end
13
+
14
+ def self.validate(base)
15
+ if !base.is_a?(Class)
16
+ raise ArgumentError, "Ree::LinkDSL should be included to named classed only"
17
+ end
18
+
19
+ if self.name.nil?
20
+ raise ArgumentError, "LinkDSL does not support anonymous classes"
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ include Ree::Args
26
+
27
+ def link(*args, **kwargs)
28
+ if args.first.is_a?(Symbol)
29
+ _link_object(*args, **kwargs)
30
+ elsif args.first.is_a?(String)
31
+ _link_file(args[0], args[1])
32
+ else
33
+ _raise_error("Invalid link DSL usage. Args should be Hash or String")
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # @param [Symbol] object_name
40
+ # @param [Nilor[Symbol]] as
41
+ # @param [Nilor[Symbol]] from
42
+ # @param [Nilor[ArrayOf[Symbol]]] methods
43
+ # @param [Nilor[Proc]] import
44
+ def _link_object(object_name, as: nil, from: nil, methods: nil, import: nil)
45
+ check_arg(object_name, :object_name, Symbol)
46
+ check_arg(as, :as, Symbol) if as
47
+ check_arg(from, :from, Symbol) if from
48
+ check_arg(import, :import, Proc) if import
49
+ check_arg_array_of(methods, :methods, Symbol) if methods
50
+
51
+ package_name = Ree::StringUtils.underscore(self.name.split('::').first).to_sym
52
+ link_package_name = from.nil? ? package_name : from
53
+ link_object_name = object_name
54
+ link_as = as ? as : object_name
55
+
56
+ _check_package_dependency_added(link_package_name, package_name)
57
+
58
+ if import
59
+ Ree::LinkImportBuilder
60
+ .new(Ree.container.packages_facade)
61
+ .build(
62
+ self,
63
+ link_package_name,
64
+ link_object_name,
65
+ import
66
+ )
67
+ end
68
+
69
+ obj = Ree
70
+ .container
71
+ .packages_facade
72
+ .load_package_object(link_package_name, link_object_name)
73
+
74
+ if obj.fn?
75
+ self.class_eval %Q(
76
+ private def _#{link_as}
77
+ @#{link_as} ||= #{obj.klass}.new
78
+ end
79
+
80
+ private def #{link_as}(*args, **kwargs, &block)
81
+ _#{link_as}.call(*args, **kwargs, &block)
82
+ end
83
+ )
84
+ else
85
+ self.class_eval %Q(
86
+ private def #{link_as}
87
+ @#{link_as} ||= #{obj.klass}.new
88
+ end
89
+ )
90
+ end
91
+ end
92
+
93
+ # @param [String] path Relative package file path ('accounts/entities/user')
94
+ # @param [Proc] proc Import constants proc
95
+ def _link_file(path, import_proc = nil)
96
+ check_arg(import_proc, :import, Proc) if import_proc
97
+
98
+ list = path.split('/')
99
+ package_name = File.basename(list[0], ".*").to_sym
100
+ current_package_name = Ree::StringUtils.underscore(self.name.split('::').first).to_sym
101
+
102
+ _check_package_dependency_added(package_name, current_package_name)
103
+
104
+ Ree.container.packages_facade.load_package_entry(package_name)
105
+ package = Ree.container.packages_facade.get_package(package_name)
106
+
107
+ file_path = File.join(
108
+ Ree::PathHelper.abs_package_dir(package),
109
+ Ree::PACKAGE, path
110
+ )
111
+
112
+ if !File.exists?(file_path)
113
+ file_path = "#{file_path}.rb"
114
+
115
+ if !File.exists?(file_path)
116
+ _raise_error("Unable to link '#{path}'. File not found #{file_path}")
117
+ end
118
+ end
119
+
120
+ Ree.container.packages_facade.load_file(file_path, package.name)
121
+
122
+ const_list = path.split('/').map { |_| Ree::StringUtils.camelize(_) }
123
+ const_short = [const_list[0], const_list.last].join("::")
124
+ const_long = const_list.join("::")
125
+
126
+ file_const = if Object.const_defined?(const_long)
127
+ Object.const_get(const_long)
128
+ elsif Object.const_defined?(const_short)
129
+ Object.const_get(const_short)
130
+ else
131
+ _raise_error("Unable to link '#{path}'. #{const_long} or #{const_short} was not defined in #{file_path}")
132
+ end
133
+
134
+ if import_proc
135
+ Ree::LinkImportBuilder
136
+ .new(Ree.container.packages_facade)
137
+ .build_for_const(
138
+ self,
139
+ file_const,
140
+ import_proc
141
+ )
142
+ end
143
+
144
+ nil
145
+ end
146
+
147
+ def _raise_error(text, code = :invalid_dsl_usage)
148
+ msg = <<~DOC
149
+ object: :#{@object.name}
150
+ path: #{Ree::PathHelper.abs_object_path(@object)}
151
+ error: #{text}
152
+ DOC
153
+
154
+ raise Ree::Error.new(msg, code)
155
+ end
156
+
157
+ def _check_package_dependency_added(package_name, current_package_name)
158
+ return if package_name == current_package_name
159
+
160
+ facade = Ree.container.packages_facade
161
+ facade.load_package_entry(package_name)
162
+ facade.load_package_entry(current_package_name)
163
+
164
+ current_package = facade.get_package(current_package_name)
165
+
166
+ dep_package = current_package.deps.detect do |d|
167
+ d.name == package_name
168
+ end
169
+
170
+ if dep_package.nil?
171
+ raise_error("Package :#{package_name} is not added as dependency for :#{current_package_name} package\npackage path: #{File.join(Ree.root_dir, current_package)}")
172
+ end
173
+ end
174
+ end
175
+ end