redis_eval 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/Gemfile +1 -1
- data/README.md +9 -49
- data/Rakefile +7 -3
- data/lib/redis_eval.rb +1 -2
- data/lib/redis_eval/script.rb +23 -28
- data/lib/redis_eval/script_set.rb +60 -0
- data/lib/redis_eval/version.rb +1 -1
- data/redis_eval.gemspec +8 -8
- metadata +14 -22
- data/.coveralls.yml +0 -1
- data/.rspec +0 -2
- data/CODE_OF_CONDUCT.md +0 -13
- data/bin/console +0 -7
- data/bin/setup +0 -7
- data/exe/redis_eval_test +0 -18
- data/lib/redis_eval/configuration.rb +0 -58
- data/lib/redis_eval/generator_methods.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 815d43d7a444de7a9d1e8f180a1f3e5f205aabdd
|
4
|
+
data.tar.gz: c2f597cdc40b93ee8505ac42a0bbba91d01d497c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bad362bcf223b7600ca11ea3717836e9f8f09aa88f5223a90a550908e7ec1462cf9fb86426ad72d1e2fe4a986d17f3a8bb0d2369b78f9b5af8c055f6233163f2
|
7
|
+
data.tar.gz: 25d4a20564c83090e9fef0b0e9147c963dd7e275be3849f3e788839f077b4a2e8d50467210efbcdd9f7afa85d00fa648d7330f89152c84738840a075bdb00bf7
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# RedisEval
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/i2bskn/redis_eval.svg)](https://travis-ci.org/i2bskn/redis_eval)
|
4
|
-
[![
|
4
|
+
[![codecov](https://codecov.io/gh/i2bskn/redis_eval/branch/master/graph/badge.svg)](https://codecov.io/gh/i2bskn/redis_eval)
|
5
5
|
|
6
6
|
Evaluate Lua scripts with Redis.
|
7
7
|
|
@@ -10,7 +10,7 @@ Evaluate Lua scripts with Redis.
|
|
10
10
|
Add this line to your application's Gemfile:
|
11
11
|
|
12
12
|
```ruby
|
13
|
-
gem
|
13
|
+
gem "redis_eval"
|
14
14
|
```
|
15
15
|
|
16
16
|
And then execute:
|
@@ -23,63 +23,23 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
## Usage
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
- `redis_options` [Hash] Generation options of Redis instance.
|
29
|
-
- `script_paths` [Array] Path to find a script file.
|
30
|
-
|
31
|
-
Example:
|
32
|
-
|
33
|
-
```ruby
|
34
|
-
RedisEval.configure do |config|
|
35
|
-
config.redis_options = { url: "redis://localhost:6379/1" }
|
36
|
-
config.script_paths = ["/path/to/script_dir"]
|
37
|
-
end
|
38
|
-
```
|
39
|
-
|
40
|
-
#### Basic usage
|
41
|
-
|
42
|
-
Build and execute the script path to argument.
|
43
|
-
|
44
|
-
```ruby
|
45
|
-
script = RedisEval.build("/path/to/script.lua")
|
46
|
-
script.execute
|
47
|
-
```
|
48
|
-
|
49
|
-
Directly by the code in the argument to build.
|
26
|
+
Build and execute a script source as argument.
|
50
27
|
|
51
28
|
```ruby
|
52
|
-
script = RedisEval::Script.new("
|
53
|
-
script.execute
|
29
|
+
script = RedisEval::Script.new("return {KEYS[1], ARGV[1]}")
|
30
|
+
script.execute([1], [2]) # => ["1", "2"]
|
54
31
|
```
|
55
32
|
|
56
|
-
|
57
|
-
|
58
|
-
To build and looking for a script from name.
|
59
|
-
This function must be set `script_paths` option.
|
33
|
+
Find and build scripts from a specific directory.
|
60
34
|
|
61
35
|
```ruby
|
62
|
-
RedisEval.
|
63
|
-
|
64
|
-
|
65
|
-
#### Script test
|
66
|
-
|
67
|
-
Test the script by execute the command.
|
68
|
-
|
69
|
-
```
|
70
|
-
$ redis_eval_test /path/to/script.lua 1 key1 argv1
|
36
|
+
scripts = RedisEval::ScriptSet.new("/path/to/script_dir")
|
37
|
+
scripts.hello.execute(keys, argv) # build /path/to/script_dir/hello.lua and run.
|
71
38
|
```
|
72
|
-
|
73
|
-
## Development
|
74
|
-
|
75
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
76
|
-
|
77
39
|
## Contributing
|
78
40
|
|
79
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/i2bskn/redis_eval.
|
80
|
-
|
41
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/i2bskn/redis_eval.
|
81
42
|
|
82
43
|
## License
|
83
44
|
|
84
45
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
85
|
-
|
data/Rakefile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
require "
|
2
|
+
require "rake/testtask"
|
3
3
|
|
4
|
-
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.libs << "lib"
|
7
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
|
+
end
|
5
9
|
|
6
|
-
task :default => :
|
10
|
+
task :default => :test
|
data/lib/redis_eval.rb
CHANGED
data/lib/redis_eval/script.rb
CHANGED
@@ -1,51 +1,46 @@
|
|
1
1
|
module RedisEval
|
2
2
|
class Script
|
3
|
-
|
3
|
+
attr_accessor :parent
|
4
|
+
attr_reader :source, :sha
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
script = File.read(path)
|
11
|
-
new(name, script)
|
12
|
-
end
|
13
|
-
|
14
|
-
def load(script)
|
15
|
-
redis.script(:load, script)
|
16
|
-
end
|
6
|
+
def self.build_from_parent(src, parent, with_load: true)
|
7
|
+
script = new(src, with_load: with_load)
|
8
|
+
script.parent = parent
|
9
|
+
script
|
10
|
+
end
|
17
11
|
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
def initialize(src, with_load: true)
|
13
|
+
@source = src
|
14
|
+
@sha = Digest::SHA1.hexdigest(@source)
|
15
|
+
@redis = nil
|
16
|
+
self.load if with_load
|
17
|
+
end
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
19
|
+
def load
|
20
|
+
redis.script(:load, source)
|
25
21
|
end
|
26
22
|
|
27
|
-
def
|
28
|
-
|
29
|
-
@script = script
|
30
|
-
@sha = Digest::SHA1.hexdigest(script)
|
23
|
+
def exist?
|
24
|
+
redis.script(:exists, sha)
|
31
25
|
end
|
32
26
|
|
33
27
|
def execute(keys = [], argv = [])
|
34
28
|
redis.evalsha(sha, Array(keys), Array(argv))
|
35
29
|
rescue Redis::CommandError => e
|
36
30
|
if e.message =~ /NOSCRIPT/
|
37
|
-
redis.eval(
|
31
|
+
redis.eval(source, Array(keys), Array(argv))
|
38
32
|
else
|
39
33
|
raise
|
40
34
|
end
|
41
35
|
end
|
42
36
|
|
43
|
-
def
|
44
|
-
redis
|
37
|
+
def redis
|
38
|
+
return @redis if @redis
|
39
|
+
parent ? parent.redis : Redis.current
|
45
40
|
end
|
46
41
|
|
47
|
-
def redis
|
48
|
-
|
42
|
+
def redis=(conn)
|
43
|
+
@redis = conn
|
49
44
|
end
|
50
45
|
end
|
51
46
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module RedisEval
|
2
|
+
class ScriptSet
|
3
|
+
attr_reader :path
|
4
|
+
|
5
|
+
SCRIPT_SUFFIX = ".lua"
|
6
|
+
|
7
|
+
def initialize(target_path, conn = nil)
|
8
|
+
@path = pathname(target_path)
|
9
|
+
@redis = conn
|
10
|
+
end
|
11
|
+
|
12
|
+
def load(name)
|
13
|
+
source = script_path(name).read
|
14
|
+
loaded_scripts[name.to_s] ||= RedisEval::Script.build_from_parent(source, self)
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_all
|
18
|
+
path.children(false).each do |child|
|
19
|
+
name = child.basename(SCRIPT_SUFFIX).to_s
|
20
|
+
source = script_path(name).read
|
21
|
+
loaded_scripts[name] ||= RedisEval::Script.build_from_parent(source, self)
|
22
|
+
end
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def redis
|
27
|
+
@redis || Redis.current
|
28
|
+
end
|
29
|
+
|
30
|
+
def redis=(conn)
|
31
|
+
@redis = conn
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def pathname(path)
|
37
|
+
path.is_a?(Pathname) ? path : Pathname.new(path)
|
38
|
+
end
|
39
|
+
|
40
|
+
def loaded_scripts
|
41
|
+
@loaded_scripts ||= {}
|
42
|
+
end
|
43
|
+
|
44
|
+
def script_path(name)
|
45
|
+
path.join(name.to_s).sub_ext(SCRIPT_SUFFIX)
|
46
|
+
end
|
47
|
+
|
48
|
+
def method_missing(name, *args, &block)
|
49
|
+
super unless respond_to?(name)
|
50
|
+
|
51
|
+
self.load(name)
|
52
|
+
define_singleton_method(name) { |*a, &b| loaded_scripts[name.to_s] }
|
53
|
+
send(name, *args, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def respond_to_missing?(name, include_private = false)
|
57
|
+
loaded_scripts.has_key?(name.to_s) || script_path(name).exist? || super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/redis_eval/version.rb
CHANGED
data/redis_eval.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "redis_eval/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "redis_eval"
|
@@ -14,17 +14,17 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = "https://github.com/i2bskn/redis_eval"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
spec.files = `git ls-files -z`.split("\x0").reject
|
18
|
-
|
19
|
-
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_dependency "redis"
|
23
23
|
|
24
|
-
spec.add_development_dependency "bundler", "~> 1.
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
25
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
-
spec.add_development_dependency "
|
26
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
27
27
|
spec.add_development_dependency "pry"
|
28
|
-
spec.add_development_dependency "
|
28
|
+
spec.add_development_dependency "codecov"
|
29
29
|
spec.add_development_dependency "simplecov"
|
30
30
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis_eval
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- i2bskn
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.14'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.14'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,19 +53,19 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '10.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
61
|
+
version: '5.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
68
|
+
version: '5.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: codecov
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -111,27 +111,19 @@ dependencies:
|
|
111
111
|
description: Evaluate Lua scripts with Redis.
|
112
112
|
email:
|
113
113
|
- i2bskn@gmail.com
|
114
|
-
executables:
|
115
|
-
- redis_eval_test
|
114
|
+
executables: []
|
116
115
|
extensions: []
|
117
116
|
extra_rdoc_files: []
|
118
117
|
files:
|
119
|
-
- ".coveralls.yml"
|
120
118
|
- ".gitignore"
|
121
|
-
- ".rspec"
|
122
119
|
- ".travis.yml"
|
123
|
-
- CODE_OF_CONDUCT.md
|
124
120
|
- Gemfile
|
125
121
|
- LICENSE.txt
|
126
122
|
- README.md
|
127
123
|
- Rakefile
|
128
|
-
- bin/console
|
129
|
-
- bin/setup
|
130
|
-
- exe/redis_eval_test
|
131
124
|
- lib/redis_eval.rb
|
132
|
-
- lib/redis_eval/configuration.rb
|
133
|
-
- lib/redis_eval/generator_methods.rb
|
134
125
|
- lib/redis_eval/script.rb
|
126
|
+
- lib/redis_eval/script_set.rb
|
135
127
|
- lib/redis_eval/version.rb
|
136
128
|
- redis_eval.gemspec
|
137
129
|
homepage: https://github.com/i2bskn/redis_eval
|
@@ -154,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
146
|
version: '0'
|
155
147
|
requirements: []
|
156
148
|
rubyforge_project:
|
157
|
-
rubygems_version: 2.
|
149
|
+
rubygems_version: 2.6.11
|
158
150
|
signing_key:
|
159
151
|
specification_version: 4
|
160
152
|
summary: Evaluate Lua scripts with Redis.
|
data/.coveralls.yml
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
repo_token: bhxUt56VkshTmwvYPRYtNwhwJhcS5RBCF
|
data/.rspec
DELETED
data/CODE_OF_CONDUCT.md
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# Contributor Code of Conduct
|
2
|
-
|
3
|
-
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
-
|
5
|
-
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
-
|
7
|
-
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
-
|
9
|
-
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
-
|
11
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
-
|
13
|
-
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/bin/console
DELETED
data/bin/setup
DELETED
data/exe/redis_eval_test
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "redis_eval"
|
5
|
-
|
6
|
-
if url = ENV["REDIS_EVAL_URL"]
|
7
|
-
RedisEval.config.redis_options = { url: url }
|
8
|
-
end
|
9
|
-
|
10
|
-
lua_script = ARGV[0] || (raise ArgumentError, "Unknown script path")
|
11
|
-
key_count = ARGV[1].to_i
|
12
|
-
argv = ARGV[2..-1] || []
|
13
|
-
|
14
|
-
raise ArgumentError, "Not enough KEYS of argument." if key_count > argv.size
|
15
|
-
keys = argv.shift(key_count)
|
16
|
-
|
17
|
-
script = RedisEval.build(lua_script)
|
18
|
-
p script.execute(keys, argv)
|
@@ -1,58 +0,0 @@
|
|
1
|
-
module RedisEval
|
2
|
-
class Configuration
|
3
|
-
module Accessible
|
4
|
-
def configure(options = {}, &block)
|
5
|
-
config.merge!(options) unless options.empty?
|
6
|
-
config.configure(&block) if block_given?
|
7
|
-
end
|
8
|
-
|
9
|
-
def config
|
10
|
-
@_config ||= Configuration.new
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
VALID_OPTIONS = [
|
15
|
-
:redis_options,
|
16
|
-
:script_paths,
|
17
|
-
].freeze
|
18
|
-
|
19
|
-
attr_accessor *VALID_OPTIONS
|
20
|
-
|
21
|
-
def initialize
|
22
|
-
reset
|
23
|
-
end
|
24
|
-
|
25
|
-
def redis(cache_disable: false)
|
26
|
-
if cache_disable
|
27
|
-
@_redis = generate_redis_connection!
|
28
|
-
else
|
29
|
-
@_redis ||= generate_redis_connection!
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def configure
|
34
|
-
yield self
|
35
|
-
end
|
36
|
-
|
37
|
-
def merge(params)
|
38
|
-
self.dup.merge!(params)
|
39
|
-
end
|
40
|
-
|
41
|
-
def merge!(params)
|
42
|
-
params.keys.each {|key| self.send("#{key}=", params[key]) }
|
43
|
-
self
|
44
|
-
end
|
45
|
-
|
46
|
-
def reset
|
47
|
-
self.redis_options = nil
|
48
|
-
self.script_paths = []
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
def generate_redis_connection!
|
53
|
-
redis_options ? Redis.new(**redis_options) : Redis.current
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
extend Configuration::Accessible
|
58
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module RedisEval
|
2
|
-
module GeneratorMethods
|
3
|
-
def build(name)
|
4
|
-
path = case name
|
5
|
-
when Pathname
|
6
|
-
name
|
7
|
-
when String, Symbol
|
8
|
-
name =~ /\.lua$/ ? pathname(name.to_s) : script_path(name)
|
9
|
-
else
|
10
|
-
raise ArgumentError
|
11
|
-
end
|
12
|
-
|
13
|
-
RedisEval::Script.build_from_path(path)
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
def pathname(path)
|
18
|
-
path.is_a?(String) ? Pathname.new(path) : path
|
19
|
-
end
|
20
|
-
|
21
|
-
def script_cache
|
22
|
-
@script_cache ||= {}
|
23
|
-
end
|
24
|
-
|
25
|
-
def script_path(name)
|
26
|
-
RedisEval.config.script_paths.each {|path|
|
27
|
-
if (script = pathname(path).join("#{name}.lua")).exist?
|
28
|
-
return script
|
29
|
-
end
|
30
|
-
}
|
31
|
-
nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def method_missing(name, *args, &block)
|
35
|
-
super unless respond_to?(name)
|
36
|
-
|
37
|
-
define_singleton_method(name) do |*a, &b|
|
38
|
-
script_cache[name.to_s] ||= build(name)
|
39
|
-
end
|
40
|
-
|
41
|
-
send(name, *args, &block)
|
42
|
-
end
|
43
|
-
|
44
|
-
def respond_to_missing?(name, include_private = false)
|
45
|
-
!!script_path(name)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
extend GeneratorMethods
|
50
|
-
end
|