with_refinements 0.4.0 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46acf7bee0e43d24b1cd6c98a3875573b0125b00b5f171c12b52947c8099d908
4
- data.tar.gz: 0ae6e9f1af73a7a30343e2030a4e28266501ed129d0a035a4cc6c74a18115c89
3
+ metadata.gz: 540b9343999aeee6303dc94c36486399f6852b5ec904114851c3b254de0805de
4
+ data.tar.gz: ba4682ae1ac92d3c2f1d3094fb75bbe39b9c02a74d88fe8d55b3383f049909a3
5
5
  SHA512:
6
- metadata.gz: 0b184d7693abd0d8efb1bf5aecc7ca4f8369eceaa7a7d92a4c6139156aaf7ccc5c7d128783c27cec1dbf5b8efacdf35489685968b6c4c04e17401edae586f335
7
- data.tar.gz: 64b53f1b80c3d79467d38ad1ad312efec6aa0f7196f1c9d73de9aeb7833f2531644c1385262013a32981a013c4b36b687e17a2ec6310555866062f6811982c15
6
+ metadata.gz: 9a2689931a6e93e4355f6f6493c3002a7de1dacbb5a6cc4c940c10a72f445b73ba8fbde9ace4eeaacbf0526319864bbd0396b61dccce978b5884af20eb5021bc
7
+ data.tar.gz: de929a1c059c4488f9381cf7dd518beb3a0384f1e0e7cdb6303e85d9d1a615cf9bb86c682e61bf8a5451ee0bd2980cfa760d79187f070ff54539c67f13130b6a
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- with_refinements (0.4.0)
4
+ with_refinements (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -2,6 +2,7 @@ require "benchmark_driver"
2
2
 
3
3
  Benchmark.driver do |x|
4
4
  x.prelude <<~RUBY
5
+ require "sin_refinements"
5
6
  require "bundler/setup"
6
7
  require "with_refinements"
7
8
 
@@ -14,18 +15,45 @@ Benchmark.driver do |x|
14
15
  end
15
16
  end
16
17
  end
18
+
19
+ module Plain
20
+ refine(String) do
21
+ def world
22
+ -"world"
23
+ end
24
+ end
25
+ end
26
+
27
+ using Plain
28
+
29
+ class String
30
+ def george
31
+ -"george"
32
+ end
33
+ end
17
34
  RUBY
18
35
 
19
- x.report 'plain', %{
20
- using M
21
- "hello".goodbye
36
+ x.report 'plain monkey patch', %{
37
+ "hello".george
38
+ }
39
+
40
+ x.report 'plain refinements', %{
41
+ "hello".world
22
42
  }
23
43
 
24
44
  x.report 'with_refinements', %{
25
45
  with_refinements(M) { "hello".goodbye }
26
46
  }
27
47
 
28
- x.report 'with_refinements(local_variables: false)', %{
29
- with_refinements(M, local_variables: false) { "hello".goodbye }
48
+ x.report 'with_refinements_light', %{
49
+ with_refinements_light(M) { "hello".goodbye }
50
+ }
51
+
52
+ x.report 'SinRefinements.refining', %{
53
+ SinRefinements.refining(M) { "hello".goodbye }
54
+ }
55
+
56
+ x.report 'SinRefinements.light_refining', %{
57
+ SinRefinements.light_refining(M) { "hello".goodbye }
30
58
  }
31
59
  end
@@ -1,15 +1,56 @@
1
1
  require "with_refinements/version"
2
2
 
3
3
  module WithRefinements
4
+ @context_cache = {}
5
+ @refined_proc_cache = Hash.new {|h,k| h[k] = {} }
6
+ @refined_proc_light_cache = Hash.new {|h,k| h[k] = {} }
7
+
4
8
  class << self
5
- def clean_binding
6
- eval('module Class.new::CleanRoom; binding; end')
9
+ def context(refinements)
10
+ @context_cache[refinements] ||= clean_binding.tap do |b|
11
+ b.local_variable_set(:__refinements__, refinements)
12
+ b.eval('__refinements__.each {|r| using r }')
13
+ end
7
14
  end
8
15
 
9
- def code_from_block(block)
16
+ def refined_proc(c, block)
17
+ @refined_proc_cache[c][block.source_location] ||= (
18
+ lvars = block.binding.local_variables
19
+ c.eval(<<~RUBY)
20
+ proc do |__binding__|
21
+ proc { |#{lvars.join(",")}|
22
+ ret = __binding__.receiver.instance_exec #{code_from_block(block)}
23
+ #{lvars.map {|v| "__binding__.local_variable_set(:#{v}, #{v})" }.join("\n")}
24
+ ret
25
+ }.call(*__binding__.local_variables.map {|v| __binding__.local_variable_get(v) })
26
+ end
27
+ RUBY
28
+ )
29
+ end
30
+
31
+ def refined_proc_light(c, block)
32
+ @refined_proc_light_cache[c][block.source_location] ||= (
33
+ c.eval(<<~RUBY)
34
+ proc { |__receiver__, __args__| __receiver__.instance_exec(*__args__) #{code_from_block(block)} }
35
+ RUBY
36
+ )
37
+ end
38
+
39
+ private
40
+
41
+ def block_source_location(block)
10
42
  iseq = RubyVM::InstructionSequence.of(block).to_a
11
43
  loc = iseq[4].yield_self {|h| h[:code_range] || h[:code_location] }
12
44
  path = iseq[7]
45
+ return path, loc
46
+ end
47
+
48
+ def clean_binding
49
+ TOPLEVEL_BINDING.eval('Module.new { break binding }')
50
+ end
51
+
52
+ def code_from_block(block)
53
+ path, loc = block_source_location(block)
13
54
  File.readlines(path)[loc[0]-1..loc[2]-1].tap {|ls|
14
55
  if loc[0] == loc[2]
15
56
  ls[0] = ls[0][loc[1]...loc[3]]
@@ -25,31 +66,19 @@ module WithRefinements
25
66
  end
26
67
  end
27
68
 
28
- refine(Object) do
29
- def with_refinements(*ms, local_variables: true, &block)
30
- # enable refinements
31
- b = WithRefinements.clean_binding
32
- b.local_variable_set(:__modules__, ms)
33
- b.eval('__modules__.each {|m| using m }')
34
-
35
- # setup block eval context
36
- bb = block.binding
37
- b.local_variable_set(:__self__, bb.receiver)
38
-
39
- # copy local_variables
40
- if local_variables
41
- bb.local_variables.each {|n| b.local_variable_set(n, bb.local_variable_get(n)) }
42
- end
69
+ def with_refinements(*refinements, &block)
70
+ c = WithRefinements.context(refinements)
71
+ p = WithRefinements.refined_proc(c, block)
72
+ p.call(block.binding)
73
+ end
43
74
 
44
- # eval block code
45
- ret = b.eval("__self__.instance_eval #{WithRefinements.code_from_block(block)}")
75
+ def with_refinements_light(*refinements, args: [], &block)
76
+ c = WithRefinements.context(refinements)
77
+ p = WithRefinements.refined_proc_light(c, block)
78
+ p.call(block.binding.receiver, args)
79
+ end
46
80
 
47
- # write back local_variables
48
- if local_variables
49
- bb.local_variables.each {|n| bb.local_variable_set(n, b.local_variable_get(n)) }
50
- end
81
+ module_function :with_refinements, :with_refinements_light
51
82
 
52
- ret
53
- end
54
- end
83
+ refine(Object) { include WithRefinements }
55
84
  end
@@ -0,0 +1,3 @@
1
+ require "with_refinements"
2
+
3
+ Object.include(WithRefinements)
@@ -1,3 +1,3 @@
1
1
  module WithRefinements
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: with_refinements
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seiei Miyagi
@@ -34,7 +34,7 @@ cert_chain:
34
34
  OKwDKKYe2ogJ/XrOjTltlugSNvq/NgD53wc4TA0F5KofdIZSJELTCUyyZMPztwI4
35
35
  OawPtyIyOegL6pM8fc7IfzLzjkdO3Bis1qFZcg==
36
36
  -----END CERTIFICATE-----
37
- date: 2018-08-02 00:00:00.000000000 Z
37
+ date: 2018-08-04 00:00:00.000000000 Z
38
38
  dependencies:
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: bundler
@@ -111,6 +111,7 @@ files:
111
111
  - examples/b.rb
112
112
  - examples/greeting.rb
113
113
  - lib/with_refinements.rb
114
+ - lib/with_refinements/core_ext.rb
114
115
  - lib/with_refinements/version.rb
115
116
  - with_refinements.gemspec
116
117
  homepage: https://github.com/hanachin/with_refinements
metadata.gz.sig CHANGED
Binary file