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,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