bade 0.3.0 → 0.3.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 202b283306b0a05d870766ff8d7c17f8312727843632958adb2bb3f2300a673f
4
- data.tar.gz: '0820f4f77eb7936b77748257faa1fd4ee51b206d4a7929c656f717127c7b2248'
3
+ metadata.gz: 9363fa63bbc18e9d9cb2af336438820127d766ef7e5b18306ddc37cdd608adfd
4
+ data.tar.gz: 6a6c86dea0211e852507fa26e7ec2d6d35b5b03469f5c6919455749134f102bd
5
5
  SHA512:
6
- metadata.gz: ecd2dbf7aa570c8051a2e1b59a1a537583cd2cd5005bb06328795de099fab4213a9cfd616a788d66e333a862253d6aecedd928632e3edb923f021e86658f6780
7
- data.tar.gz: 8633aba2120eaf8f60f96a357cde8eda8c32d862e92dca3c060f66c014bf1031e5bc2916077ee1d1a7de6494cc62c426ded062065c664949acaf849fce71de66
6
+ metadata.gz: 37b06b4ef4aa918a88e96c5bfd164ef5d41b9bc0e22949d857b3af143e6dcb462d41f8c10e880f29f4a201e0ca115309e4734e46268f0b1c6fc9f0c7c50802d2
7
+ data.tar.gz: a828c7d9c09450235b719c37381add83dcd0980d256f97b755dd6b5ceb287a1f6baca4f43a04c00523cf45a1d692aac6d7b7abd79f8b5694fe713f3686ceefa0
data/Bade.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  lib = File.expand_path('lib', __dir__)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'utils/where'
4
+
3
5
  module Bade
4
6
  module Runtime
5
7
  # Tracks created global variables and constants in block.
@@ -10,9 +12,16 @@ module Bade
10
12
  # @return [Array<[Object, :Symbol]>]
11
13
  attr_accessor :caught_constants
12
14
 
13
- def initialize
15
+ # @return [Array<String>, nil]
16
+ attr_accessor :constants_location_prefixes
17
+
18
+ # @param [Array<String>, nil] constants_location_prefixes If given, only constants whose location starts with one
19
+ # of the prefixes will be removed. If nil, all constants
20
+ # will be removed.
21
+ def initialize(constants_location_prefixes: nil)
14
22
  @caught_variables = []
15
23
  @caught_constants = []
24
+ @constants_location_prefixes = constants_location_prefixes
16
25
  end
17
26
 
18
27
  # @yieldreturn [T]
@@ -43,8 +52,8 @@ module Bade
43
52
  end
44
53
 
45
54
  def clear_constants
46
- @caught_constants.each do |(obj, name)|
47
- obj.send(:remove_const, name) if obj.const_defined?(name)
55
+ _filtered_constants.each do |(obj, name)|
56
+ obj.send(:remove_const, name)
48
57
  end
49
58
  @caught_constants = []
50
59
  end
@@ -54,6 +63,26 @@ module Bade
54
63
  eval("#{name} = nil", binding, __FILE__, __LINE__)
55
64
  end
56
65
  end
66
+
67
+ # Filteres caught constants by location prefixes and returns ones that should be removed.
68
+ #
69
+ # @return [Array<[Object, :Symbol]>]
70
+ def _filtered_constants
71
+ @caught_constants.select do |(obj, name)|
72
+ next unless obj.const_defined?(name)
73
+ next true if constants_location_prefixes.nil?
74
+
75
+ konst = obj.const_get(name)
76
+ begin
77
+ location = Bade.where_is(konst)
78
+ rescue ::ArgumentError
79
+ next
80
+ end
81
+
82
+ path = location.first
83
+ constants_location_prefixes&.any? { |prefix| path.start_with?(prefix) }
84
+ end
85
+ end
57
86
  end
58
87
  end
59
88
  end
@@ -86,7 +86,7 @@ module Bade
86
86
  # @param [String] filename
87
87
  def __load(filename)
88
88
  # FakeFS does not fake `load` method
89
- if defined?(:FakeFS) && FakeFS.activated?
89
+ if Object.const_defined?(:FakeFS) && Object.const_get(:FakeFS).activated?
90
90
  # rubocop:disable Security/Eval
91
91
  eval(File.read(filename), __get_binding, filename)
92
92
  # rubocop:enable Security/Eval
@@ -98,7 +98,7 @@ module Bade
98
98
  # @param [String] filename
99
99
  def require_relative(filename)
100
100
  # FakeFS does not fake `require_relative` method
101
- if defined?(:FakeFS) && FakeFS.activated?
101
+ if Object.const_defined?(:FakeFS) && Object.const_get(:FakeFS).activated?
102
102
  # rubocop:disable Security/Eval
103
103
  eval(File.read(filename), __get_binding, filename)
104
104
  # rubocop:enable Security/Eval
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Inspired by https://gist.github.com/wtaysom/1236979
4
+
5
+ module Bade
6
+ module Where
7
+ class << self
8
+ def is_proc(proc)
9
+ source_location(proc)
10
+ end
11
+
12
+ def is_method(klass, method_name)
13
+ source_location(klass.method(method_name))
14
+ end
15
+
16
+ def is_instance_method(klass, method_name)
17
+ source_location(klass.instance_method(method_name))
18
+ end
19
+
20
+ def are_methods(klass, method_name)
21
+ are_via_extractor(:method, klass, method_name)
22
+ end
23
+
24
+ def are_instance_methods(klass, method_name)
25
+ are_via_extractor(:method, klass, method_name)
26
+ end
27
+
28
+ def is_class(klass)
29
+ defined_methods(klass)
30
+ .group_by { |sl| sl[0] }
31
+ .map do |file, sls|
32
+ lines = sls.map { |sl| sl[1] }
33
+ count = lines.size
34
+ line = lines.min
35
+
36
+ {
37
+ file: file,
38
+ count: count,
39
+ line: line
40
+ }
41
+ end
42
+ .sort_by { |fc| fc[:count] }
43
+ .map { |fc| [fc[:file], fc[:line]] }
44
+ end
45
+
46
+ # Raises ArgumentError if klass does not have any Ruby methods defined in it.
47
+ def is_class_primarily(klass)
48
+ source_locations = is_class(klass)
49
+ if source_locations.empty?
50
+ methods = defined_methods(klass)
51
+ msg = if methods.empty?
52
+ "#{klass} has no methods"
53
+ else
54
+ "#{klass} only has built-in methods (#{methods.size} in total)"
55
+ end
56
+
57
+ raise ::ArgumentError, msg
58
+ end
59
+ source_locations[0]
60
+ end
61
+
62
+ private
63
+
64
+ def source_location(method)
65
+ method.source_location || (
66
+ method.to_s =~ /: (.*)>/
67
+ Regexp.last_match(1)
68
+ )
69
+ end
70
+
71
+ def are_via_extractor(extractor, klass, method_name)
72
+ klass.ancestors
73
+ .map do |ancestor|
74
+ method = ancestor.send(extractor, method_name)
75
+ source_location(method) if method.owner == ancestor
76
+ end
77
+ .compact
78
+ end
79
+
80
+ def defined_methods(klass)
81
+ methods = klass.methods(false).map { |m| klass.method(m) } +
82
+ klass.instance_methods(false).map { |m| klass.instance_method(m) }
83
+ methods
84
+ .map(&:source_location)
85
+ .compact
86
+ end
87
+ end
88
+ end
89
+
90
+ def self.where_is(klass, method = nil)
91
+ if method
92
+ begin
93
+ Where.is_instance_method(klass, method)
94
+ rescue NameError
95
+ Where.is_method(klass, method)
96
+ end
97
+ else
98
+ Where.is_class_primarily(klass)
99
+ end
100
+ end
101
+ end
data/lib/bade/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bade
4
- VERSION = '0.3.0'.freeze
4
+ VERSION = '0.3.1'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bade
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Kříž
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-21 00:00:00.000000000 Z
11
+ date: 2022-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: psych
@@ -112,6 +112,7 @@ files:
112
112
  - lib/bade/runtime/globals_tracker.rb
113
113
  - lib/bade/runtime/mixin.rb
114
114
  - lib/bade/runtime/render_binding.rb
115
+ - lib/bade/runtime/utils/where.rb
115
116
  - lib/bade/version.rb
116
117
  homepage: https://github.com/epuber-io/bade
117
118
  licenses:
@@ -133,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
134
  - !ruby/object:Gem::Version
134
135
  version: '0'
135
136
  requirements: []
136
- rubygems_version: 3.3.8
137
+ rubygems_version: 3.3.9
137
138
  signing_key:
138
139
  specification_version: 4
139
140
  summary: Minimalistic template engine for Ruby.