named_imports 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/named_imports.rb +71 -49
- data/lib/named_imports/error.rb +35 -0
- data/lib/named_imports/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb15d783f22496923d8eb7770bc934347bbd84a0019fad85380e3e43a29361d7
|
4
|
+
data.tar.gz: fb90680e03f17db882f40cd38e93e3d51c729177d90e67bc7b6f5d82fd99fe8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 498ea8dd7a20b2e9a5070e2edfa97b31911b471fa93fe28800ad076f69b031b1132ea5bc65d12db206b52c5bb0dd1903dd41ff611fa1b637cb5aa16947bf0445
|
7
|
+
data.tar.gz: 88c609ed4e0649b998752474c78d6496978b1adc5144fe294a0ed770561f0120668977c75885fe8e605748f22a137f08b3d2541becd23e8ab2a92d1c2a9db8f1
|
data/lib/named_imports.rb
CHANGED
@@ -1,79 +1,101 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "named_imports/version"
|
4
|
+
require_relative "named_imports/error"
|
4
5
|
|
5
6
|
module NamedImports
|
6
|
-
class Error < StandardError; end
|
7
|
-
|
8
7
|
class << self
|
9
|
-
def from(
|
10
|
-
|
11
|
-
|
8
|
+
def from(raw_path, constant_names, context = Object)
|
9
|
+
into_path, import_line = caller_path_and_line
|
10
|
+
from_path = full_path_for_import(from_path: raw_path, into_path: into_path)
|
11
|
+
sandbox = sandbox_eval(file_path: from_path)
|
12
|
+
load_constants(constant_names, from_sandbox: sandbox, into_context: context)
|
13
|
+
end
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
def import(context = Object, &block)
|
16
|
+
into_path, import_line = caller_path_and_line
|
17
|
+
constant_names = []
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
begin
|
20
|
+
block.call
|
21
|
+
rescue => e
|
22
|
+
constant_name = constant_name_from_error(e)
|
20
23
|
|
21
|
-
|
22
|
-
NamedImports.
|
24
|
+
if constant_name.nil?
|
25
|
+
raise NamedImports::Error::ImportBlockError.new(into_path, import_line, e)
|
23
26
|
end
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
context.send(:remove_const, constant_name) if context.const_defined?(constant_name, false)
|
29
|
-
context.const_set(constant_name, anon_mod.const_get(constant_name))
|
28
|
+
if !constant_names.include?(constant_name)
|
29
|
+
constant_names << constant_name
|
30
|
+
context.const_set(constant_name, nil)
|
30
31
|
end
|
32
|
+
|
33
|
+
retry
|
31
34
|
end
|
35
|
+
|
36
|
+
constant_names
|
32
37
|
end
|
33
38
|
|
34
|
-
def
|
35
|
-
|
39
|
+
def make_named_imports_available(in_context: Object)
|
40
|
+
def_method = in_context == Object ? :define_method : :define_singleton_method
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
raise e unless /uninitialized constant /.match?(e.message)
|
42
|
+
in_context.send(def_method, :from) do |path, constants|
|
43
|
+
NamedImports.from(path, constants, in_context)
|
44
|
+
end
|
41
45
|
|
42
|
-
|
43
|
-
|
46
|
+
in_context.send(def_method, :import) do |&block|
|
47
|
+
NamedImports.import(in_context, &block)
|
48
|
+
end
|
49
|
+
end
|
44
50
|
|
45
|
-
|
46
|
-
raise NameError, "unable to import constant: #{e.message.gsub(/uninitialized constant /, '')}"
|
47
|
-
end
|
51
|
+
private
|
48
52
|
|
49
|
-
|
53
|
+
def caller_path_and_line
|
54
|
+
caller_path_info = caller(3..3).first
|
55
|
+
caller_path_info.match(/\A(.+?):(\d+):/)[1..2]
|
56
|
+
end
|
50
57
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
58
|
+
def full_path_for_import(from_path:, into_path:)
|
59
|
+
ext = %r{[^/]+\.[^/]+$}.match?(from_path) ? "" : ".rb"
|
60
|
+
from_path_with_ext = "#{from_path}#{ext}"
|
61
|
+
importer_dir = File.dirname(into_path)
|
62
|
+
File.expand_path(from_path_with_ext, importer_dir)
|
63
|
+
end
|
55
64
|
|
56
|
-
|
57
|
-
|
65
|
+
def catchable_missing_constant_error?(error)
|
66
|
+
error.is_a?(NameError) && error.message =~ /uninitialized constant /
|
67
|
+
end
|
58
68
|
|
59
|
-
|
69
|
+
def constant_name_from_error(error)
|
70
|
+
return unless error.is_a?(NameError)
|
71
|
+
constant_matcher = /uninitialized constant (?:#<Module:[^>]+>::)?(\w*(?:::\w+)*)$/
|
72
|
+
constant_match = error.message.match(constant_matcher)
|
73
|
+
constant_match && constant_match[1]
|
60
74
|
end
|
61
75
|
|
62
|
-
|
76
|
+
def read_content(file_path:)
|
77
|
+
File.open(file_path, &:read)
|
78
|
+
end
|
63
79
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
80
|
+
def sandbox_eval(file_path:)
|
81
|
+
sandbox_module = Module.new
|
82
|
+
make_named_imports_available(in_context: sandbox_module)
|
83
|
+
ruby_code = read_content(file_path: file_path)
|
84
|
+
sandbox_module.class_eval(ruby_code, file_path)
|
85
|
+
sandbox_module
|
69
86
|
end
|
70
|
-
end
|
71
87
|
|
72
|
-
|
73
|
-
|
74
|
-
|
88
|
+
def load_constants(constant_names, from_sandbox:, into_context:)
|
89
|
+
constant_names.each do |constant_name|
|
90
|
+
if into_context.const_defined?(constant_name, false)
|
91
|
+
into_context.send(:remove_const, constant_name)
|
92
|
+
end
|
75
93
|
|
76
|
-
|
77
|
-
|
94
|
+
sandboxed_constant = from_sandbox.const_get(constant_name)
|
95
|
+
into_context.const_set(constant_name, sandboxed_constant)
|
96
|
+
end
|
97
|
+
end
|
78
98
|
end
|
99
|
+
|
100
|
+
make_named_imports_available
|
79
101
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NamedImports
|
4
|
+
module Error
|
5
|
+
class Base < ::StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class ImportBlockError < NamedImports::Error::Base
|
9
|
+
def initialize(importer_file, importer_line, original_error = nil)
|
10
|
+
error_details = []
|
11
|
+
error_details << "Something went wrong when evaluating the named import at #{importer_file}:#{importer_line}."
|
12
|
+
error_details << "This is likely to be an error in your 'import' block."
|
13
|
+
if original_error
|
14
|
+
original_error_class = original_error.class.to_s
|
15
|
+
article = original_error_class[0].match(/aeiou/i) ? "an" : "a"
|
16
|
+
error_details << "The original error was #{article} #{original_error_class}: #{original_error.message}"
|
17
|
+
end
|
18
|
+
|
19
|
+
error_message = error_details.join(" ")
|
20
|
+
super(error_message)
|
21
|
+
|
22
|
+
set_backtrace(original_error.backtrace) if original_error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class ImportError < ::NameError
|
27
|
+
end
|
28
|
+
|
29
|
+
class ConstantImportError < NamedImports::Error::ImportError
|
30
|
+
def initialize(imported_name, imported_file, importer_file, importer_line)
|
31
|
+
super("Unable to import #{imported_name} from #{imported_file} (import occurs in #{importer_file}:#{importer_line})")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: named_imports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keegan Leitz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -156,6 +156,7 @@ files:
|
|
156
156
|
- bin/console
|
157
157
|
- bin/setup
|
158
158
|
- lib/named_imports.rb
|
159
|
+
- lib/named_imports/error.rb
|
159
160
|
- lib/named_imports/version.rb
|
160
161
|
- named_imports.gemspec
|
161
162
|
homepage: https://github.com/kjleitz/named_imports
|