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,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class MethodDecorator
5
+ class << self
6
+ def decorator_id(target, method_name, is_class_method)
7
+ "#{target.object_id}#{target.name}#{method_name}#{is_class_method}"
8
+ end
9
+
10
+ def add_decorator(decorator)
11
+ decorators[decorator.id] = decorator
12
+ end
13
+
14
+ def get_decorator(id)
15
+ decorators[id]
16
+ end
17
+
18
+ def decorators
19
+ @decorators ||= {}
20
+ end
21
+ end
22
+
23
+ include Ree::Args
24
+
25
+ attr_reader :target # [Class] class ot superclass of decorated method
26
+ attr_reader :method_name # [Symbol] original method name
27
+ attr_reader :method_parameters # [Array] list of original method parameters
28
+ attr_reader :is_class_method # [Bool]
29
+ attr_reader :contract_definition # [ContractDefinition] definition of contract
30
+ attr_reader :errors # [Nilor[ArrayOf[Class]]] list of thrown errors
31
+ attr_reader :doc # [Nilor[String]] rdoc
32
+ attr_reader :args # [CalledArgsValidator]
33
+ attr_reader :return_validator # [BaseValidator] validator for return value
34
+
35
+ def initialize(method_name, is_class_method, target)
36
+ check_arg(method_name, :method_name, Symbol)
37
+ check_bool(is_class_method, :is_class_method)
38
+ check_arg_any(target, :target, [Class, Module])
39
+
40
+ engine = Engine.fetch_for(target)
41
+
42
+ @method_name = method_name
43
+ @is_class_method = is_class_method
44
+ @target = target
45
+ @contract_definition = engine.fetch_contract
46
+ @errors = engine.fetch_errors
47
+ @doc = engine.fetch_doc
48
+ end
49
+
50
+ def call
51
+ return if Ree::Contracts.no_contracts?
52
+ return unless contract_definition
53
+
54
+ self.class.add_decorator(self)
55
+
56
+ @method_parameters = alias_target
57
+ .instance_method(method_name)
58
+ .parameters
59
+ .freeze
60
+
61
+ @args = CalledArgsValidator.new(
62
+ contract_definition,
63
+ method_parameters,
64
+ printed_name
65
+ )
66
+
67
+ @return_validator = Validators.fetch_for(contract_definition.return_contract)
68
+
69
+ make_alias
70
+ make_definition
71
+ end
72
+
73
+ def execute_on(target, args, kwargs, &blk)
74
+ @args.call(args, kwargs, blk)
75
+ result = target.send(method_alias, *args, **kwargs, &blk)
76
+
77
+ if !return_validator.call(result)
78
+ raise ReturnContractError, "Invalid return value for #{printed_name}\n #{
79
+ return_validator.message(result, 'returns', 0).strip
80
+ }"
81
+ end
82
+
83
+ result
84
+ end
85
+
86
+ # Unique ID of this Method Decorator
87
+ def id
88
+ @id ||= self.class.decorator_id(target, method_name, is_class_method)
89
+ end
90
+
91
+ # Alias name for original method
92
+ def method_alias
93
+ @method_alias ||= :"__original_#{method_name}_#{SecureRandom.hex}"
94
+ end
95
+
96
+ # Target class to be used for alias method definition
97
+ def alias_target
98
+ @alias_target ||= begin
99
+ return Utils.eigenclass_of(target) if is_class_method
100
+ target
101
+ end
102
+ end
103
+
104
+ private
105
+
106
+ def make_alias
107
+ alias_target.alias_method(method_alias, method_name)
108
+ end
109
+
110
+ def make_definition
111
+ file, line = alias_target.instance_method(method_alias).source_location
112
+
113
+ alias_target.class_eval(%Q(
114
+ def #{method_name}(*args, **kwargs, &blk)
115
+ decorator = Ree::Contracts::MethodDecorator.get_decorator('#{id}')
116
+ decorator.execute_on(self, args, kwargs, &blk)
117
+ end
118
+ ), file, line - 3)
119
+
120
+ make_private if private_method?
121
+ make_protected if protected_method?
122
+ end
123
+
124
+ def private_method?
125
+ return target.private_methods.include?(method_alias) if is_class_method
126
+ target.private_instance_methods.include?(method_alias)
127
+ end
128
+
129
+ def protected_method?
130
+ return target.protected_methods.include?(method_alias) if is_class_method
131
+ target.protected_instance_methods.include?(method_alias)
132
+ end
133
+
134
+ def make_private
135
+ _method_name = method_name
136
+ _method_alias = method_alias
137
+
138
+ alias_target.class_eval do
139
+ private _method_name
140
+ private _method_alias
141
+ end
142
+ end
143
+
144
+ def make_protected
145
+ _method_name = method_name
146
+ _method_alias = method_alias
147
+
148
+ alias_target.class_eval do
149
+ protected _method_name
150
+ protected _method_alias
151
+ end
152
+ end
153
+
154
+ def printed_name
155
+ @printed_name ||= "#{target}#{is_class_method ? '.' : '#'}#{method_name}"
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ module Truncatable
5
+ def truncate(str, limit = 80)
6
+ str.length > limit ? "#{str[0..limit]}..." : str
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ module Utils
5
+ def self.eigenclass_of(target)
6
+ class << target; self; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class ArrayValidator < BaseValidator
5
+ attr_reader :validators
6
+
7
+ def initialize(contract)
8
+ super(contract)
9
+ @validators = contract.map { |cont| Validators.fetch_for(cont) }
10
+ end
11
+
12
+ def to_s
13
+ "[#{validators.map(&:to_s).join(', ')}]"
14
+ end
15
+
16
+ def call(value)
17
+ return false unless value.is_a?(Array) && value.length == validators.length
18
+
19
+ value.zip(validators).all? do |val, validator|
20
+ validator.call(val)
21
+ end
22
+ end
23
+
24
+ def message(value, name, lvl = 1)
25
+ unless value.is_a?(Array)
26
+ return "expected Array, got #{value.class} => #{truncate(value.inspect)}"
27
+ end
28
+
29
+ unless value.length == validators.length
30
+ return "expected to have #{validators.length} #{pluralize(validators.length, 'item', 'items')}, got #{value.length} #{pluralize(value.length, 'item', 'items')} => #{truncate(value.inspect)}"
31
+ end
32
+
33
+ errors = []
34
+ sps = " " * lvl
35
+
36
+ value.zip(validators).each_with_index do |(val, validator), idx|
37
+ next if validator.call(val)
38
+
39
+ msg = validator.message(val, "#{name}[#{idx}]", lvl + 1)
40
+ errors << "\n\t#{sps} - #{name}[#{idx}]: #{msg}"
41
+
42
+ if errors.size > 3
43
+ errors << "\n\t#{sps} - ..."
44
+ break
45
+ end
46
+ end
47
+
48
+ errors.join
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class BaseValidator
5
+ include Ree::Contracts::Truncatable
6
+
7
+ attr_reader :contract
8
+
9
+ def initialize(contract)
10
+ @contract = contract
11
+ end
12
+
13
+ def to_s
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def call(value)
18
+ raise NotImplementedError
19
+ end
20
+
21
+ private
22
+
23
+ def pluralize(num, single, plural)
24
+ num == 1 ? single : plural
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class ClassValidator < BaseValidator
5
+ def call(value)
6
+ value.is_a?(contract)
7
+ end
8
+
9
+ def to_s
10
+ contract.name
11
+ end
12
+
13
+ def message(value, _name, _lvl = 1)
14
+ "expected #{contract}, got #{value.class} => #{truncate(value.inspect)}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class DefaultValidator < BaseValidator
5
+ def call(value)
6
+ contract == value
7
+ end
8
+
9
+ def to_s
10
+ truncate(
11
+ contract.respond_to?(:to_s) ? contract.to_s : contract.inspect,
12
+ 10
13
+ )
14
+ end
15
+
16
+ def message(value, _name, _lvl = 1)
17
+ "expected #{truncate(contract.inspect, 40)}, got #{truncate(value.inspect, 40)}"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module Ree::Contracts
6
+ class HashValidator < BaseValidator
7
+ attr_reader :opt_dict, :validators
8
+
9
+ def initialize(contract)
10
+ super(contract)
11
+
12
+ @opt_dict = Set.new
13
+
14
+ @validators = contract
15
+ .transform_values { |cont| Validators.fetch_for(cont) }
16
+ .transform_keys { |key|
17
+ next key unless key.is_a?(String) || key.is_a?(Symbol)
18
+
19
+ key_str = key.to_s
20
+ next key unless key_str.end_with?('?') && key_str.length > 1
21
+
22
+ opt_key = key_str[0..-2]
23
+ opt_key = opt_key.to_sym if key.is_a? Symbol
24
+ @opt_dict << opt_key
25
+
26
+ opt_key
27
+ }
28
+ end
29
+
30
+ def call(value)
31
+ return false unless value.is_a?(Hash)
32
+ return false unless value.all? { |key, _| validators.has_key?(key) }
33
+
34
+ validators.all? do |key, validator|
35
+ value.has_key?(key) ? validator.call(value[key]) : optional?(key)
36
+ end
37
+ end
38
+
39
+ def to_s
40
+ "{#{validators.map { |k, v| "#{key_to_s(k)} => #{v.to_s}" }.join(', ')}}"
41
+ end
42
+
43
+ def message(value, name, lvl = 1)
44
+ unless value.is_a?(Hash)
45
+ return "expected Hash, got #{value.class} => #{truncate(value.inspect)}"
46
+ end
47
+
48
+ errors = []
49
+ sps = " " * lvl
50
+
51
+ validators.each do |key, validator|
52
+ if errors.size > 3
53
+ errors << "\n\t#{sps} - ..."
54
+ break
55
+ end
56
+
57
+ unless value.key?(key)
58
+ errors << "\n\t#{sps} - #{name}[#{key.inspect}]: missing" unless optional?(key)
59
+ next
60
+ end
61
+
62
+ val = value[key]
63
+ next if validator.call(val)
64
+
65
+ msg = validator.message(val, "#{name}[#{key.inspect}]", lvl + 1)
66
+ errors << "\n\t#{sps} - #{name}[#{key.inspect}]: #{msg}"
67
+ end
68
+
69
+ value.each do |key, val|
70
+ if errors.size > 3
71
+ errors << "\n\t#{sps} - ..."
72
+ break
73
+ end
74
+
75
+ next if validators.key?(key)
76
+
77
+ errors << "\n\t#{sps} - #{name}[#{key.inspect}]: unexpected"
78
+ end
79
+
80
+ errors.join
81
+ end
82
+
83
+ private
84
+
85
+ def key_to_s(key)
86
+ k =if optional?(key)
87
+ v = "#{key}?"
88
+ key.is_a?(String) ? v : v.to_sym
89
+ else
90
+ key
91
+ end
92
+
93
+ k.inspect
94
+ end
95
+
96
+ def optional?(key)
97
+ opt_dict.include?(key)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class ProcValidator < BaseValidator
5
+ def call(value)
6
+ contract.call value
7
+ end
8
+
9
+ def to_s
10
+ 'Proc#call'
11
+ end
12
+
13
+ def message(value, name, lvl = 1)
14
+ "proc validation failed for #{truncate(value.inspect)}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class RangeValidator < BaseValidator
5
+ def call(value)
6
+ contract.include? value
7
+ end
8
+
9
+ def to_s
10
+ contract.inspect
11
+ end
12
+
13
+ def message(value, _name, _lvl = 1)
14
+ "expected value to be in range #{contract}, got #{truncate(value.inspect)}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class RegexpValidator < BaseValidator
5
+ def call(value)
6
+ value =~ contract
7
+ end
8
+
9
+ def to_s
10
+ contract.to_s
11
+ end
12
+
13
+ def message(value, name, lvl = 1)
14
+ "expected to match #{contract.to_s}, got #{truncate(value.inspect)}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ree::Contracts
4
+ class ValidValidator < BaseValidator
5
+ def call(value)
6
+ contract.valid? value
7
+ end
8
+
9
+ def to_s
10
+ if contract.respond_to?(:to_s)
11
+ contract.to_s
12
+ else
13
+ klass = contract.is_a?(Class) ? contract : contract.class
14
+ klass.name
15
+ end
16
+ end
17
+
18
+ def message(value, name, lvl = 1)
19
+ if contract.respond_to?(:message)
20
+ contract.message(value, name, lvl)
21
+ else
22
+ obj_name = contract.is_a?(Class) ? contract : contract.class
23
+ op = contract.is_a?(Class) ? '.' : '#'
24
+ "#{obj_name}#{op}valid? failed for #{truncate(value.inspect)}"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module Ree::Contracts
6
+ class Validators
7
+ FORBIDDEN_CONTRACTS = Set.new([
8
+ ArgContracts::None, ArgContracts::Kwargs,
9
+ ArgContracts::Block, ArgContracts::Optblock,
10
+ ArgContracts::SplatOf, ArgContracts::Splat
11
+ ])
12
+
13
+ class << self
14
+ def fetch_for(contract)
15
+ validators[contract.object_id] ||= build(contract)
16
+ end
17
+
18
+ private
19
+
20
+ def build(contract)
21
+ if FORBIDDEN_CONTRACTS.include?(contract)
22
+ name = contract.name.split("::").last
23
+ raise Ree::Error.new("#{name} is not supported arg validator", :invalid_dsl_usage)
24
+ end
25
+
26
+ return ProcValidator.new(contract) if contract.is_a?(Proc)
27
+ return ArrayValidator.new(contract) if contract.is_a?(Array)
28
+ return HashValidator.new(contract) if contract.is_a?(Hash)
29
+ return RangeValidator.new(contract) if contract.is_a?(Range)
30
+ return RegexpValidator.new(contract) if contract.is_a?(Regexp)
31
+ return ValidValidator.new(contract) if contract.respond_to?(:valid?)
32
+ return ClassValidator.new(contract) if contract.is_a?(Class) || contract.is_a?(Module)
33
+
34
+ DefaultValidator.new(contract)
35
+ end
36
+
37
+ def validators
38
+ @validators ||= {}
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal = true
2
+
3
+ require 'securerandom'
4
+ require 'forwardable'
5
+ require 'delegate'
6
+
7
+ module Ree::Contracts
8
+ autoload :ArgContracts, 'ree/contracts/arg_contracts'
9
+ autoload :ArrayValidator, 'ree/contracts/validators/array_validator'
10
+ autoload :BadContractError, 'ree/contracts/errors/bad_contract_error'
11
+ autoload :BaseValidator, 'ree/contracts/validators/base_validator'
12
+ autoload :CalledArgsValidator, 'ree/contracts/called_args_validator'
13
+ autoload :ClassValidator, 'ree/contracts/validators/class_validator'
14
+ autoload :Contractable, 'ree/contracts/contractable'
15
+ autoload :ContractDefinition, 'ree/contracts/contract_definition'
16
+ autoload :ContractError, 'ree/contracts/errors/contract_error'
17
+ autoload :Core, 'ree/contracts/core'
18
+ autoload :DefaultValidator, 'ree/contracts/validators/default_validator'
19
+ autoload :Engine, 'ree/contracts/engine'
20
+ autoload :EngineProxy, 'ree/contracts/engine_proxy'
21
+ autoload :Error, 'ree/contracts/errors/error'
22
+ autoload :HashValidator, 'ree/contracts/validators/hash_validator'
23
+ autoload :MethodDecorator, 'ree/contracts/method_decorator'
24
+ autoload :ProcValidator, 'ree/contracts/validators/proc_validator'
25
+ autoload :RangeValidator, 'ree/contracts/validators/range_validator'
26
+ autoload :RegexpValidator, 'ree/contracts/validators/regexp_validator'
27
+ autoload :ReturnContractError, 'ree/contracts/errors/return_contract_error'
28
+ autoload :Truncatable, 'ree/contracts/truncatable'
29
+ autoload :Utils, 'ree/contracts/utils'
30
+ autoload :Validators, 'ree/contracts/validators'
31
+ autoload :ValidValidator, 'ree/contracts/validators/valid_validator'
32
+
33
+ def self.no_contracts?
34
+ ENV["NO_CONTRACTS"]
35
+ end
36
+
37
+ def self.get_method_decorator(target, method_name, scope: :instance)
38
+ unless scope == :instance || scope == :class
39
+ raise Ree::Error.new(':scope should be either :class or :instance', :invalid_dsl_usage)
40
+ end
41
+
42
+ decorator_id = MethodDecorator.decorator_id(target, method_name, scope == :class)
43
+ MethodDecorator.get_decorator(decorator_id)
44
+ end
45
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal = true
2
+
3
+ class Ree::LinkValidator
4
+ def initialize(packages_facade)
5
+ @packages_facade = packages_facade
6
+ end
7
+
8
+ # Validates existance and uniqueness of linked object
9
+ # @param [Ree::Object] object
10
+ # @param [Ree::ObjectLink] link
11
+ # @return [nil]
12
+ def call(object, link)
13
+ link_package = @packages_facade.get_package(link.package_name)
14
+ link_object = link_package.get_object(link.object_name)
15
+
16
+ if !link_object
17
+ msg = <<~DOC
18
+ object: :#{object.name}
19
+ path: #{Ree::PathHelper.abs_object_path(object)}
20
+ error: Unable to find :#{link.object_name} in :#{link.package_name} package
21
+ DOC
22
+
23
+ raise Ree::Error.new(msg, :invalid_dsl_usage)
24
+ end
25
+
26
+ existing_link = link_object.links.detect do |inj|
27
+ inj.object_name == link.object_name && inj.package_name == link.package_name
28
+ end
29
+
30
+ if existing_link
31
+ msg = <<~DOC
32
+ object: :#{object.name}
33
+ path: #{Ree::PathHelper.abs_object_path(object)}
34
+ error: Duplicate link :#{link.object_name}
35
+ DOC
36
+
37
+ raise Ree::Error.new(msg, :invalid_dsl_usage)
38
+ end
39
+
40
+ nil
41
+ end
42
+ end