exec_env 0.1.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 +7 -0
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.txt +22 -0
- data/README.md +61 -0
- data/Rakefile +1 -0
- data/exec_env.gemspec +24 -0
- data/lib/exec_env.rb +6 -0
- data/lib/exec_env/env.rb +89 -0
- data/lib/exec_env/version.rb +3 -0
- data/spec/exec_env/env_spec.rb +152 -0
- data/spec/spec_helper.rb +1 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e5b8c15180ac50f0722afdd0987350185e01cd58
|
4
|
+
data.tar.gz: 8eecab2c95e0911dcbfac7ab45cb42bbfc71bb8f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cd306141d63b7bdb8cbc8a209a08048a3054d931652298c6904866a92d4dedf5ae779a58dd3c9ca3be2bfff6bf7b41ecc755300a447374aa92ac4a117478a54a
|
7
|
+
data.tar.gz: b29a6a804a923f7ef7d238d077ccc38633486767e1b5e4dc14227a226d48e3d9a35badc4cb11b114ec6d33c833a9e81dcb5c92c326098e20daa4db78bfb1063d
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
exec_env (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.4)
|
10
|
+
rake (10.1.0)
|
11
|
+
rspec (2.14.1)
|
12
|
+
rspec-core (~> 2.14.0)
|
13
|
+
rspec-expectations (~> 2.14.0)
|
14
|
+
rspec-mocks (~> 2.14.0)
|
15
|
+
rspec-core (2.14.4)
|
16
|
+
rspec-expectations (2.14.0)
|
17
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
18
|
+
rspec-mocks (2.14.1)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
bundler (~> 1.4)
|
25
|
+
exec_env!
|
26
|
+
rake (~> 10.1)
|
27
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Marten Lienen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# ExecEnv
|
2
|
+
|
3
|
+
Execute blocks in a manipulatable environment and capture messages
|
4
|
+
that did not get a response and would normally produce a `NameError`
|
5
|
+
or `NoMethodError`. For example use cases of this have a look at
|
6
|
+
[anaphoric](https://github.com/CQQL/anaphoric) or
|
7
|
+
[hash_builder](https://github.com/CQQL/hash_builder).
|
8
|
+
|
9
|
+
If you have another use case for this, please send me an email. I am
|
10
|
+
really interested if there are other use cases for this quite exotic
|
11
|
+
library.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
gem 'exec_env'
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install exec_env
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
scope = [1, 2, 3, 4]
|
31
|
+
|
32
|
+
env = ExecEnv::Env.new(locals: { foo: 2 })
|
33
|
+
env.locals[:bar] = 3
|
34
|
+
env.scope = scope
|
35
|
+
|
36
|
+
result = env.exec do
|
37
|
+
exotic :dragon, :banana
|
38
|
+
action do
|
39
|
+
:nested
|
40
|
+
end
|
41
|
+
|
42
|
+
size * foo * bar
|
43
|
+
end
|
44
|
+
|
45
|
+
# Because the block was executed in the scope of the array.
|
46
|
+
result # => 24 == 2 * 3 * 4
|
47
|
+
|
48
|
+
env.messages
|
49
|
+
# => [
|
50
|
+
# => [:exotic, [:dragon, :banana], nil],
|
51
|
+
# => [:action, [], <Proc ...>]
|
52
|
+
# => ]
|
53
|
+
```
|
54
|
+
|
55
|
+
## Contributing
|
56
|
+
|
57
|
+
1. Fork it ( http://github.com/CQQL/exec_env/fork )
|
58
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
59
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
60
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
61
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/exec_env.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'exec_env/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "exec_env"
|
8
|
+
spec.version = ExecEnv::VERSION
|
9
|
+
spec.authors = ["Marten Lienen"]
|
10
|
+
spec.email = ["marten.lienen@gmail.com"]
|
11
|
+
spec.summary = %q{Execute blocks in a manipulatable environment}
|
12
|
+
spec.description = %q{See README.md}
|
13
|
+
spec.homepage = "https://github.com/CQQL/exec_env"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.4"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.1"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
end
|
data/lib/exec_env.rb
ADDED
data/lib/exec_env/env.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
module ExecEnv
|
2
|
+
# A manipulatable execution environment, that let's you inject local and
|
3
|
+
# instance variables into a block and capture messages sent during it's
|
4
|
+
# execution.
|
5
|
+
class Env
|
6
|
+
# A hash of local variables, that will be injected into the block
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# env.locals = { foo: 3, bar: :symbol }
|
11
|
+
attr_accessor :locals
|
12
|
+
|
13
|
+
# A hash of instance variables, that will be injected into the block
|
14
|
+
#
|
15
|
+
# Examples
|
16
|
+
#
|
17
|
+
# env.ivars = { :@foo => 3, :@bar => :symbol }
|
18
|
+
attr_accessor :ivars
|
19
|
+
|
20
|
+
# An object, that will serve as the scope of execution of the block
|
21
|
+
#
|
22
|
+
# Examples
|
23
|
+
#
|
24
|
+
# # Unresolved method calls in the block will be forwarded to
|
25
|
+
# # the String object "An object"
|
26
|
+
# env.scope = "An object"
|
27
|
+
attr_accessor :scope
|
28
|
+
|
29
|
+
# An array of all messages that were not captured by locals or
|
30
|
+
# the scope object.
|
31
|
+
#
|
32
|
+
# Examples
|
33
|
+
#
|
34
|
+
# env.exec do
|
35
|
+
# test :foo, "bar"
|
36
|
+
# each do
|
37
|
+
# # ...
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# env.messages
|
42
|
+
# # => [[:test, [:foo, "bar], nil], [:each, [], <the block>]]
|
43
|
+
attr_reader :messages
|
44
|
+
|
45
|
+
def initialize (locals: {}, ivars: {}, scope: nil)
|
46
|
+
@messages = []
|
47
|
+
@locals = locals
|
48
|
+
@ivars = ivars
|
49
|
+
@scope = scope
|
50
|
+
end
|
51
|
+
|
52
|
+
# Execute a block in the manipulated environment.
|
53
|
+
#
|
54
|
+
# Additional arguments will be passed to the block.
|
55
|
+
#
|
56
|
+
# Returns the return value of the block
|
57
|
+
def exec (*args, &block)
|
58
|
+
if @scope
|
59
|
+
@scope.instance_variables.each do |name|
|
60
|
+
instance_variable_set(name, @scope.instance_variable_get(name))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
@ivars.each do |name, value|
|
65
|
+
instance_variable_set(name, value)
|
66
|
+
end
|
67
|
+
|
68
|
+
instance_exec(*args, &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Send a message, that completely bypasses the locals
|
72
|
+
# and the scope and is added directly to #messages.
|
73
|
+
def xsend (name, *args, &block)
|
74
|
+
@messages << [name, args, block]
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing (name, *args, &block)
|
78
|
+
if @locals.key?(name) && args.size == 0 && !block
|
79
|
+
@locals[name]
|
80
|
+
elsif @scope && @scope.respond_to?(name)
|
81
|
+
@scope.send(name, *args, &block)
|
82
|
+
else
|
83
|
+
@messages << [name, args, block]
|
84
|
+
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
describe ExecEnv::Env do
|
2
|
+
let(:env) { ExecEnv::Env.new }
|
3
|
+
|
4
|
+
it "should allow injecting locals" do
|
5
|
+
value = nil
|
6
|
+
|
7
|
+
env.locals = { it: 5 }
|
8
|
+
env.exec do
|
9
|
+
value = it
|
10
|
+
end
|
11
|
+
|
12
|
+
expect(value).to eq 5
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should allow injecting instance variables" do
|
16
|
+
value = nil
|
17
|
+
|
18
|
+
env.ivars = { :@bind => :test }
|
19
|
+
env.exec do
|
20
|
+
value = @bind
|
21
|
+
end
|
22
|
+
|
23
|
+
expect(value).to eq :test
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should dispatch method calls to the scope object" do
|
27
|
+
value = nil
|
28
|
+
scope = Object.new
|
29
|
+
def scope.it
|
30
|
+
"value"
|
31
|
+
end
|
32
|
+
|
33
|
+
env.scope = scope
|
34
|
+
env.exec do
|
35
|
+
value = it
|
36
|
+
end
|
37
|
+
|
38
|
+
expect(value).to eq "value"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should inject instance variables from the scope object" do
|
42
|
+
value = nil
|
43
|
+
scope = Object.new
|
44
|
+
scope.instance_variable_set(:@symbol, :value)
|
45
|
+
|
46
|
+
env.scope = scope
|
47
|
+
env.exec do
|
48
|
+
value = @symbol
|
49
|
+
end
|
50
|
+
|
51
|
+
expect(value).to eq :value
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should dispatch method calls to the scope" do
|
55
|
+
value = nil
|
56
|
+
scope = Object.new
|
57
|
+
def scope.it (value)
|
58
|
+
value
|
59
|
+
end
|
60
|
+
|
61
|
+
env.scope = scope
|
62
|
+
env.locals = { it: :binding }
|
63
|
+
env.exec do
|
64
|
+
value = it(:scope)
|
65
|
+
end
|
66
|
+
|
67
|
+
expect(value).to eq :scope
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should evaluate locals before scope methods" do
|
71
|
+
value = nil
|
72
|
+
scope = Object.new
|
73
|
+
def scope.it
|
74
|
+
:scope
|
75
|
+
end
|
76
|
+
|
77
|
+
env.scope = scope
|
78
|
+
env.locals = { it: :binding }
|
79
|
+
env.exec do
|
80
|
+
value = it
|
81
|
+
end
|
82
|
+
|
83
|
+
expect(value).to eq :binding
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should overshadow scope ivars with explicit ones" do
|
87
|
+
value = nil
|
88
|
+
scope = Object.new
|
89
|
+
scope.instance_variable_set(:@it, :scope)
|
90
|
+
|
91
|
+
env.scope = scope
|
92
|
+
env.ivars = { :@it => :binding }
|
93
|
+
env.exec do
|
94
|
+
value = @it
|
95
|
+
end
|
96
|
+
|
97
|
+
expect(value).to eq :binding
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should track unresolved messages" do
|
101
|
+
block = -> { :block }
|
102
|
+
scope = Object.new
|
103
|
+
def scope.number
|
104
|
+
10
|
105
|
+
end
|
106
|
+
|
107
|
+
env.locals = { foo: 5 }
|
108
|
+
env.scope = scope
|
109
|
+
env.exec do
|
110
|
+
var = foo
|
111
|
+
var += number
|
112
|
+
|
113
|
+
foo 15
|
114
|
+
name(:var, 33, &block)
|
115
|
+
end
|
116
|
+
|
117
|
+
expect(env.messages).to eq [[:foo, [15], nil], [:name, [:var, 33], block]]
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should allow bypassing locals and the scope with xsend" do
|
121
|
+
scope = Object.new
|
122
|
+
def scope.foo (arg)
|
123
|
+
:in_scope
|
124
|
+
end
|
125
|
+
|
126
|
+
env.scope = scope
|
127
|
+
env.locals = { foo: 12 }
|
128
|
+
env.exec do
|
129
|
+
xsend :foo, 37
|
130
|
+
end
|
131
|
+
|
132
|
+
expect(env.messages).to eq [[:foo, [37], nil]]
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should pass arguments to the block" do
|
136
|
+
value = nil
|
137
|
+
|
138
|
+
env.exec -10, 3 do |num, factor|
|
139
|
+
value = num * factor
|
140
|
+
end
|
141
|
+
|
142
|
+
expect(value).to eq -30
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should return the return value of the block" do
|
146
|
+
value = env.exec do
|
147
|
+
1337
|
148
|
+
end
|
149
|
+
|
150
|
+
expect(value).to eq 1337
|
151
|
+
end
|
152
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "exec_env"
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: exec_env
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marten Lienen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.4'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: See README.md
|
56
|
+
email:
|
57
|
+
- marten.lienen@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .rspec
|
64
|
+
- Gemfile
|
65
|
+
- Gemfile.lock
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- exec_env.gemspec
|
70
|
+
- lib/exec_env.rb
|
71
|
+
- lib/exec_env/env.rb
|
72
|
+
- lib/exec_env/version.rb
|
73
|
+
- spec/exec_env/env_spec.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
homepage: https://github.com/CQQL/exec_env
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.1.5
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Execute blocks in a manipulatable environment
|
99
|
+
test_files:
|
100
|
+
- spec/exec_env/env_spec.rb
|
101
|
+
- spec/spec_helper.rb
|