benry-recorder 1.0.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/README.md +125 -0
- data/Rakefile.rb +21 -0
- data/benry-recorder.gemspec +36 -0
- data/lib/benry/recorder.rb +178 -0
- data/task/common-task.rb +185 -0
- data/task/readme-task.rb +105 -0
- data/test/recorder_test.rb +186 -0
- data/test/run_all.rb +7 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4546395dc9bc48dd67bd730e86d6b2875fffb556
|
4
|
+
data.tar.gz: c1d7c6b23e60e2b0b735aff167b6af5ef5ce8398
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 86785e3485c6dbfa1e89737dd3259f8ab1f828209e66b43254900085bca4326ede38246f84d2d0007958114362818cecd4b02d61545de7bdbf8908ef06f9575e
|
7
|
+
data.tar.gz: 7df326f888d5f522a16ef5004273b032a99356de9fa578b3016ccff8eada31bf7c0a0e4c21cdb5077c616ddedada26435f71e84d0c68ac4f8a0ec480df05863b
|
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
<!-- -*- coding: utf-8 -*- -->
|
2
|
+
# Benry-recorder README
|
3
|
+
|
4
|
+
Benry-recoder is a tiny utility that can:
|
5
|
+
|
6
|
+
* Record method calls of target object.
|
7
|
+
* Define fake methods on target object.
|
8
|
+
* Create fake object which has fake methods.
|
9
|
+
|
10
|
+
|
11
|
+
## Table of Contents
|
12
|
+
|
13
|
+
<!-- TOC -->
|
14
|
+
|
15
|
+
* <a href="#how-to-record-method-calls">How to record method calls</a>
|
16
|
+
* <a href="#how-to-define-fake-methods">How to define fake methods</a>
|
17
|
+
* <a href="#how-to-create-fake-object">How to create fake object</a>
|
18
|
+
* <a href="#license-and-copyright">License and Copyright</a>
|
19
|
+
|
20
|
+
<!-- /TOC -->
|
21
|
+
|
22
|
+
|
23
|
+
## How to record method calls
|
24
|
+
|
25
|
+
<!--
|
26
|
+
file: example1.rb
|
27
|
+
-->
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'benry/recorder'
|
31
|
+
|
32
|
+
class Calc
|
33
|
+
def average(*nums) # average() calls total()
|
34
|
+
return total(*nums) / nums.length
|
35
|
+
end
|
36
|
+
def total(*nums)
|
37
|
+
t = 0; nums.each {|n| t += n }
|
38
|
+
return t # or: return nums.sum
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
## target object
|
43
|
+
calc = Calc.new
|
44
|
+
|
45
|
+
## record method calls
|
46
|
+
rec = Benry::Recorder.new
|
47
|
+
rec.record(calc, :total, :average)
|
48
|
+
|
49
|
+
## call methods
|
50
|
+
calc.average(10, 20, 30, 40) # calls calc.total() internally
|
51
|
+
|
52
|
+
## details of method calls
|
53
|
+
p rec.length #=> 2
|
54
|
+
puts rec.inspect
|
55
|
+
#=> 0: #<Calc:0x001234abcd>.average(10, 20, 30, 40) #=> 25
|
56
|
+
# 1: #<Calc:0x001234abcd>.total(10, 20, 30, 40) #=> 100
|
57
|
+
#
|
58
|
+
p rec[0].obj #=> #<Calc:0x001234abcd>
|
59
|
+
p rec[0].obj.equal?(calc) #=> true
|
60
|
+
p rec[0].name #=> :average
|
61
|
+
p rec[0].args #=> [10, 20, 30, 40]
|
62
|
+
p rec[0].ret #=> 25
|
63
|
+
#
|
64
|
+
p rec[1].obj #=> #<Calc:0x001234abcd>
|
65
|
+
p rec[1].obj.equal?(calc) #=> true
|
66
|
+
p rec[1].name #=> :total
|
67
|
+
p rec[1].args #=> [10, 20, 30, 40]
|
68
|
+
p rec[1].ret #=> 100
|
69
|
+
#
|
70
|
+
p rec[0].to_a #=> [obj, :average, [10, 20, 30, 40], 25]
|
71
|
+
p rec[1].to_a #=> [obj, :total, [10, 20, 30, 40], 100]
|
72
|
+
```
|
73
|
+
|
74
|
+
|
75
|
+
## How to define fake methods
|
76
|
+
|
77
|
+
<!--
|
78
|
+
file: example2.rb
|
79
|
+
-->
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
require 'benry/recorder'
|
83
|
+
|
84
|
+
class Calc
|
85
|
+
....(snip)....
|
86
|
+
end
|
87
|
+
|
88
|
+
## target object
|
89
|
+
calc = Calc.new
|
90
|
+
|
91
|
+
## before
|
92
|
+
p calc.total(10, 20, 30, 40) #=> 100
|
93
|
+
p calc.average(10, 20, 30, 40) #=> 25
|
94
|
+
|
95
|
+
## define fake methods
|
96
|
+
rec = Benry::Recorder.new
|
97
|
+
rec.fake_method(calc, :total=>123, :average=>34)
|
98
|
+
|
99
|
+
## after
|
100
|
+
p calc.total(10, 20, 30, 40) #=> 123
|
101
|
+
p calc.average(10, 20, 30, 40) #=> 34
|
102
|
+
```
|
103
|
+
|
104
|
+
|
105
|
+
## How to create fake object
|
106
|
+
|
107
|
+
<!--
|
108
|
+
file: example3.rb
|
109
|
+
-->
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
require 'benry/recorder'
|
113
|
+
|
114
|
+
rec = Benry::Recorder.new
|
115
|
+
obj = rec.fake_object(:foo=>10, :bar=>20)
|
116
|
+
p obj.foo() #=> 10
|
117
|
+
p obj.bar() #=> 20
|
118
|
+
p obj.bar(3, 4, 'a'=>5) # accepts any arguments
|
119
|
+
```
|
120
|
+
|
121
|
+
|
122
|
+
## License and Copyright
|
123
|
+
|
124
|
+
* $License: MIT License $
|
125
|
+
* $Copyright: copyright(c) 2011-2021 kuwata-lab.com all rights reserved $
|
data/Rakefile.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
PROJECT = "benry-recorder"
|
5
|
+
RELEASE = ENV['RELEASE'] || "0.0.0"
|
6
|
+
COPYRIGHT = "copyright(c) 2011-2021 kuwata-lab.com all rights reserved"
|
7
|
+
LICENSE = "MIT License"
|
8
|
+
|
9
|
+
README_EXTRACT = /^file: (.*\.rb)/
|
10
|
+
|
11
|
+
Dir.glob("./task/*.rb").each {|x| require_relative x }
|
12
|
+
|
13
|
+
def readme_extract_callback(filename, str)
|
14
|
+
if filename == 'example1.rb'
|
15
|
+
str =~ /class Calc\n(.*?)^end\n/m
|
16
|
+
$_classdef = $1
|
17
|
+
elsif filename == 'example2.rb'
|
18
|
+
str = str.sub(/^ *\.\.\.+\(snip\)\.\.\.+ *\n/, $_classdef)
|
19
|
+
end
|
20
|
+
return str
|
21
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'benry-recorder'
|
5
|
+
spec.version = '$Release: 1.0.0 $'.split()[1]
|
6
|
+
spec.author = 'kwatch'
|
7
|
+
spec.email = 'kwatch@gmail.com'
|
8
|
+
spec.platform = Gem::Platform::RUBY
|
9
|
+
spec.homepage = 'https://github.com/kwatch/benry-ruby/tree/ruby/benry-recorder'
|
10
|
+
spec.summary = "Record method calls, or define fake methods."
|
11
|
+
spec.description = <<-'END'
|
12
|
+
Benry-recorder is a tiny utility that can:
|
13
|
+
|
14
|
+
* Record method calls of target object.
|
15
|
+
* Define fake methods on target object.
|
16
|
+
* Create fake object which has fake methods.
|
17
|
+
END
|
18
|
+
spec.license = 'MIT'
|
19
|
+
spec.files = Dir[
|
20
|
+
'README.md', 'MIT-LICENSE', #'CHANGES.md'
|
21
|
+
'Rakefile.rb', 'benry-recorder.gemspec',
|
22
|
+
#'bin/*',
|
23
|
+
'lib/**/*.rb',
|
24
|
+
'test/**/*.rb',
|
25
|
+
'task/**/*.rb',
|
26
|
+
]
|
27
|
+
#spec.executables = ['benry-recorder']
|
28
|
+
#spec.bindir = 'bin'
|
29
|
+
spec.require_path = 'lib'
|
30
|
+
#spec.test_files = Dir['test/run_all.rb']
|
31
|
+
spec.test_files = Dir['test/**/*_test.rb']
|
32
|
+
#spec.extra_rdoc_files = ['README.md', 'CHANGES.md']
|
33
|
+
|
34
|
+
spec.add_development_dependency 'minitest' , '~> 0'
|
35
|
+
spec.add_development_dependency 'minitest-ok' , '~> 0'
|
36
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
###
|
4
|
+
### $Release: 1.0.0 $
|
5
|
+
### $Copyright: copyright(c) 2011-2021 kuwata-lab.com all rights reserved $
|
6
|
+
### $License: MIT License $
|
7
|
+
###
|
8
|
+
|
9
|
+
|
10
|
+
module Benry
|
11
|
+
|
12
|
+
|
13
|
+
##
|
14
|
+
## record method calls, or define fake methods.
|
15
|
+
##
|
16
|
+
## ex. record method calls
|
17
|
+
## ## target class
|
18
|
+
## class Calc
|
19
|
+
## def average(*nums) # average() calls total()
|
20
|
+
## return total(*nums) / nums.length
|
21
|
+
## end
|
22
|
+
## def total(*nums)
|
23
|
+
## t = 0; nums.each {|n| t += n }
|
24
|
+
## return t # or: return nums.sum
|
25
|
+
## end
|
26
|
+
## end
|
27
|
+
## ## record method calls
|
28
|
+
## rec = Benry::Recorder.new
|
29
|
+
## calc = Calc.new
|
30
|
+
## rec.record(calc, :total, :average)
|
31
|
+
## ## call methods
|
32
|
+
## calc.average(10, 20, 30, 40)
|
33
|
+
## ## details of method calls
|
34
|
+
## p rec.length #=> 2
|
35
|
+
## puts rec.inspect
|
36
|
+
## #=> 0: #<Calc:0x001234abcd>.average(10, 20, 30, 40) #=> 25
|
37
|
+
## # 1: #<Calc:0x001234abcd>.total(10, 20, 30, 40) #=> 100
|
38
|
+
## #
|
39
|
+
## p rec[0].obj #=> #<Calc:0x001234abcd>
|
40
|
+
## p rec[0].obj.equal?(calc) #=> true
|
41
|
+
## p rec[0].name #=> :average
|
42
|
+
## p rec[0].args #=> [10, 20, 30, 40]
|
43
|
+
## p rec[0].ret #=> 25
|
44
|
+
## #
|
45
|
+
## p rec[1].obj #=> #<Calc:0x001234abcd>
|
46
|
+
## p rec[1].obj.equal?(calc) #=> true
|
47
|
+
## p rec[1].name #=> :total
|
48
|
+
## p rec[1].args #=> [10, 20, 30, 40]
|
49
|
+
## p rec[1].ret #=> 100
|
50
|
+
## #
|
51
|
+
## p rec[0].to_a #=> [obj, :average, [10, 20, 30, 40], 25]
|
52
|
+
## p rec[1].to_a #=> [obj, :total, [10, 20, 30, 40], 100]
|
53
|
+
##
|
54
|
+
## ex. fake method
|
55
|
+
## rec = Benry::Recorder.new
|
56
|
+
## calc = Calc.new
|
57
|
+
## ## before
|
58
|
+
## p calc.total(10, 20, 30, 40) #=> 100
|
59
|
+
## p calc.average(10, 20, 30, 40) #=> 25
|
60
|
+
## ## after
|
61
|
+
## rec.fake_method(calc, :total=>123, :average=>34)
|
62
|
+
## p calc.total(10, 20, 30, 40) #=> 123
|
63
|
+
## p calc.average(10, 20, 30, 40) #=> 34
|
64
|
+
##
|
65
|
+
## ex. fake object
|
66
|
+
## rec = Benry::Recorder.new
|
67
|
+
## obj = rec.fake_object(:foo=>10, :bar=>20)
|
68
|
+
## p obj.foo() #=> 10
|
69
|
+
## p obj.bar() #=> 20
|
70
|
+
## p obj.bar(3, 4, 'a'=>5) # accepts any arguments
|
71
|
+
##
|
72
|
+
class Recorder
|
73
|
+
|
74
|
+
|
75
|
+
class Called
|
76
|
+
|
77
|
+
def initialize(obj, name, args, ret)
|
78
|
+
@obj = obj
|
79
|
+
@name = name
|
80
|
+
@args = args
|
81
|
+
@ret = ret
|
82
|
+
end
|
83
|
+
|
84
|
+
#; [!m98p9] returns receiver object.
|
85
|
+
#; [!es61g] returns method name.
|
86
|
+
#; [!2yeeo] returns arguments.
|
87
|
+
#; [!yd3hl] returns arguments.
|
88
|
+
attr_accessor :obj, :name, :args, :ret
|
89
|
+
|
90
|
+
def to_a()
|
91
|
+
#; [!hrol9] returns array of obj, nae, args, and ret.
|
92
|
+
return [@obj, @name, @args, @ret]
|
93
|
+
end
|
94
|
+
|
95
|
+
def inspect()
|
96
|
+
#; [!g2iwe] represents internal data.
|
97
|
+
s = args.collect {|arg| arg.inspect }.join(", ")
|
98
|
+
return "#{obj.inspect}.#{name}(#{s}) #=> #{ret.inspect}"
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def initialize()
|
105
|
+
@called = []
|
106
|
+
end
|
107
|
+
|
108
|
+
def length()
|
109
|
+
@called.length
|
110
|
+
end
|
111
|
+
|
112
|
+
alias size length
|
113
|
+
|
114
|
+
def [](index)
|
115
|
+
return @called[index]
|
116
|
+
end
|
117
|
+
|
118
|
+
def inspect()
|
119
|
+
#; [!k85bz] represents internal data.
|
120
|
+
buf = []
|
121
|
+
@called.each_with_index {|called, i| buf << "#{i}: #{called.inspect}\n" }
|
122
|
+
return buf.join()
|
123
|
+
end
|
124
|
+
|
125
|
+
def record_method(obj, *method_names)
|
126
|
+
#; [!61z3j] records method calls.
|
127
|
+
called_list = @called
|
128
|
+
proc_obj = proc do |obj, name, orig_method|
|
129
|
+
(class << obj; self; end).class_eval do
|
130
|
+
alias_method orig_method, name
|
131
|
+
define_method(name) do |*args|
|
132
|
+
called = Recorder::Called.new(obj, name.to_s.intern, args, nil)
|
133
|
+
called_list << called
|
134
|
+
#; [!9kh1f] calls original method.
|
135
|
+
ret = obj.__send__(orig_method, *args)
|
136
|
+
called.ret = ret
|
137
|
+
ret
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
method_names.each do |name|
|
142
|
+
proc_obj.call(obj, name, "__#{name}_orig".intern)
|
143
|
+
end
|
144
|
+
self
|
145
|
+
end
|
146
|
+
alias record record_method
|
147
|
+
|
148
|
+
def fake_method(obj, **name_and_values)
|
149
|
+
#; [!g112x] defines fake methods.
|
150
|
+
called_list = @called
|
151
|
+
proc_obj = proc do |obj, name, val|
|
152
|
+
(class << obj; self; end).class_eval do
|
153
|
+
#; [!kgvm1] defined methods can can take any arguments.
|
154
|
+
define_method(name) do |*args|
|
155
|
+
called_list << Recorder::Called.new(obj, name, args, val)
|
156
|
+
val
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
name_and_values.each do |name, val|
|
161
|
+
proc_obj.call(obj, name, val)
|
162
|
+
end
|
163
|
+
#; [!2p1b0] returns self.
|
164
|
+
self
|
165
|
+
end
|
166
|
+
alias fake fake_method
|
167
|
+
|
168
|
+
def fake_object(**name_and_values)
|
169
|
+
#; [!hympr] creates fake object.
|
170
|
+
obj = Object.new
|
171
|
+
fake_method(obj, **name_and_values)
|
172
|
+
return obj
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
end
|
data/task/common-task.rb
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
defined? PROJECT or abort "PROJECT required."
|
5
|
+
defined? RELEASE or abort "RELEASE required."
|
6
|
+
defined? COPYRIGHT or abort "COPYRIGHT required."
|
7
|
+
defined? LICENSE or abort "LICENSE required."
|
8
|
+
|
9
|
+
RELEASE =~ /\A\d+\.\d+\.\d+/ or abort "RELEASE=#{RELEASE}: invalid release number."
|
10
|
+
|
11
|
+
$ruby_versions ||= %w[2.4 2.5 2.6 2.7 3.0]
|
12
|
+
|
13
|
+
|
14
|
+
require 'rake/clean'
|
15
|
+
CLEAN << "build"
|
16
|
+
CLEAN.concat Dir.glob("#{PROJECT}-*.gem").collect {|x| x.sub(/\.gem$/, '') }
|
17
|
+
CLOBBER.concat Dir.glob("#{PROJECT}-*.gem")
|
18
|
+
|
19
|
+
|
20
|
+
desc "show release guide"
|
21
|
+
task :guide do
|
22
|
+
RELEASE != '0.0.0' or abort "rake help: required 'RELEASE=X.X.X'"
|
23
|
+
rel, proj = RELEASE, PROJECT
|
24
|
+
rel =~ /(\d+\.\d+)/
|
25
|
+
branch = "#{proj}_rel-#{$1}"
|
26
|
+
puts <<END
|
27
|
+
How to release:
|
28
|
+
|
29
|
+
$ git diff .
|
30
|
+
$ git status .
|
31
|
+
$ which ruby
|
32
|
+
$ rake test
|
33
|
+
$ rake test:all
|
34
|
+
$ rake readme:execute # optional
|
35
|
+
$ rake readme:toc # optional
|
36
|
+
$ rake package RELEASE=#{rel}
|
37
|
+
$ rake package:extract # confirm files in gem file
|
38
|
+
$ (cd #{proj}-#{rel}/data; find . -type f)
|
39
|
+
$ gem install #{proj}-#{rel}.gem # confirm gem package
|
40
|
+
$ gem uninstall #{proj}
|
41
|
+
$ gem push #{proj}-#{rel}.gem # publish gem to rubygems.org
|
42
|
+
$ git tag #{proj}-#{rel}
|
43
|
+
$ git push
|
44
|
+
$ git push --tags
|
45
|
+
END
|
46
|
+
end unless Rake::Task.task_defined?(:guide)
|
47
|
+
|
48
|
+
|
49
|
+
desc "do test"
|
50
|
+
task :test do
|
51
|
+
ruby "test/run_all.rb"
|
52
|
+
end unless Rake::Task.task_defined?(:test)
|
53
|
+
|
54
|
+
|
55
|
+
if ENV['VS_HOME'] && $ruby_versions
|
56
|
+
desc "do test for different ruby versions"
|
57
|
+
task :'test:all' do
|
58
|
+
vs_home = ENV['VS_HOME'].split(/:/).first
|
59
|
+
ENV['TC_QUIET'] = "Y" if File.exist?("test/tc.rb")
|
60
|
+
comp = proc {|x, y| x.to_s.split('.').map(&:to_i) <=> y.to_s.split('.').map(&:to_i) }
|
61
|
+
$ruby_versions.each do |ver|
|
62
|
+
dir = Dir.glob("#{vs_home}/ruby/#{ver}.*").sort_by(&comp).last
|
63
|
+
next unless dir
|
64
|
+
puts "==== ruby #{ver} (#{dir}) ===="
|
65
|
+
sh "#{dir}/bin/ruby test/run_all.rb" do |ok, res|
|
66
|
+
$stderr.puts "** test failed" unless ok
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end unless Rake::Task.task_defined?(:'test:all')
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def target_files()
|
74
|
+
$_target_files ||= begin
|
75
|
+
spec_src = File.read("#{PROJECT}.gemspec", encoding: 'utf-8')
|
76
|
+
spec = eval spec_src
|
77
|
+
spec.name == PROJECT or
|
78
|
+
abort "'#{PROJECT}' != '#{spec.name}' (project name in gemspec file)"
|
79
|
+
spec.files
|
80
|
+
end
|
81
|
+
return $_target_files
|
82
|
+
end
|
83
|
+
|
84
|
+
def edit_file(filename)
|
85
|
+
File.open(filename, 'rb+') do |f|
|
86
|
+
s1 = f.read()
|
87
|
+
s2 = yield s1
|
88
|
+
if s1 != s2
|
89
|
+
f.rewind()
|
90
|
+
f.truncate(0)
|
91
|
+
f.write(s2)
|
92
|
+
true
|
93
|
+
else
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
desc "edit metadata in files"
|
101
|
+
task :edit do
|
102
|
+
target_files().each do |fname|
|
103
|
+
changed = edit_file(fname) do |s|
|
104
|
+
#s = s.gsub(/\$Release[:].*?\$/, "$"+"Release: #{RELEASE} $")
|
105
|
+
s = s.gsub(/\$Copyright[:].*?\$/, "$"+"Copyright: #{COPYRIGHT} $")
|
106
|
+
s = s.gsub(/\$License[:].*?\$/, "$"+"License: #{LICENSE} $")
|
107
|
+
s
|
108
|
+
end
|
109
|
+
puts "[C] #{fname}" if changed
|
110
|
+
puts "[U] #{fname}" unless changed
|
111
|
+
end
|
112
|
+
end unless Rake::Task.task_defined?(:edit)
|
113
|
+
|
114
|
+
|
115
|
+
desc "create package (*.gem)"
|
116
|
+
task :package do
|
117
|
+
RELEASE != '0.0.0' or abort "rake help: required 'RELEASE=X.X.X'"
|
118
|
+
## copy
|
119
|
+
dir = "build"
|
120
|
+
rm_rf dir if File.exist?(dir)
|
121
|
+
mkdir dir
|
122
|
+
target_files().each do |file|
|
123
|
+
dest = File.join(dir, File.dirname(file))
|
124
|
+
mkdir_p dest, :verbose=>false unless File.exist?(dest)
|
125
|
+
cp file, "#{dir}/#{file}"
|
126
|
+
end
|
127
|
+
## edit
|
128
|
+
Dir.glob("#{dir}/**/*").each do |file|
|
129
|
+
next unless File.file?(file)
|
130
|
+
edit_file(file) do |s|
|
131
|
+
s = s.gsub(/\$Release[:].*?\$/, "$"+"Release: #{RELEASE} $")
|
132
|
+
s = s.gsub(/\$Copyright[:].*?\$/, "$"+"Copyright: #{COPYRIGHT} $")
|
133
|
+
s = s.gsub(/\$License[:].*?\$/, "$"+"License: #{LICENSE} $")
|
134
|
+
s
|
135
|
+
end
|
136
|
+
end
|
137
|
+
## build
|
138
|
+
chdir dir do
|
139
|
+
sh "gem build #{PROJECT}.gemspec"
|
140
|
+
end
|
141
|
+
mv "#{dir}/#{PROJECT}-#{RELEASE}.gem", "."
|
142
|
+
rm_rf dir
|
143
|
+
end unless Rake::Task.task_defined?(:package)
|
144
|
+
|
145
|
+
|
146
|
+
desc "extract latest gem file"
|
147
|
+
task :'package:extract' do
|
148
|
+
gemfile = Dir.glob("#{PROJECT}-*.gem").sort_by {|x| File.mtime(x) }.last
|
149
|
+
dir = gemfile.sub(/\.gem$/, '')
|
150
|
+
rm_rf dir if File.exist?(dir)
|
151
|
+
mkdir dir
|
152
|
+
mkdir "#{dir}/data"
|
153
|
+
cd dir do
|
154
|
+
sh "tar xvf ../#{gemfile}"
|
155
|
+
sh "gunzip *.gz"
|
156
|
+
cd "data" do
|
157
|
+
sh "tar xvf ../data.tar"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end unless Rake::Task.task_defined?(:'package:extract')
|
161
|
+
|
162
|
+
|
163
|
+
desc "upload gem file to rubygems.org"
|
164
|
+
task :publish do
|
165
|
+
RELEASE != '0.0.0' or abort "rake help: required 'RELEASE=X.X.X'"
|
166
|
+
gemfile = "#{PROJECT}-#{RELEASE}.gem"
|
167
|
+
print "** Are you sure to publish #{gemfile}? [y/N]: "
|
168
|
+
answer = $stdin.gets().strip()
|
169
|
+
if answer.downcase == "y"
|
170
|
+
sh "gem push #{gemfile}"
|
171
|
+
sh "git tag ruby-#{PROJECT}-#{RELEASE}"
|
172
|
+
sh "#git push --tags"
|
173
|
+
end
|
174
|
+
end unless Rake::Task.task_defined?(:publish)
|
175
|
+
|
176
|
+
|
177
|
+
desc nil
|
178
|
+
task :'relink' do
|
179
|
+
Dir.glob("task/*.rb").each do |x|
|
180
|
+
src = "../" + x
|
181
|
+
next if File.identical?(src, x)
|
182
|
+
rm x
|
183
|
+
ln src, x
|
184
|
+
end
|
185
|
+
end
|
data/task/readme-task.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
README_FILE = "README.md" unless defined? README_FILE
|
4
|
+
README_EXTRACT = /^file: +(\S+)/ unless defined? README_EXTRACT
|
5
|
+
README_CODESTART = /^```\w+$/ unless defined? README_CODESTART
|
6
|
+
README_CODEEND = /^```$/ unless defined? README_CODEEND
|
7
|
+
README_DESTDIR = "tmp/readme" unless defined? README_DESTDIR
|
8
|
+
|
9
|
+
require 'rake/clean'
|
10
|
+
CLEAN << "README.html"
|
11
|
+
|
12
|
+
|
13
|
+
def readme_extract_callback(filename, str)
|
14
|
+
return str
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
namespace :readme do
|
19
|
+
|
20
|
+
desc "retrieve scripts from #{README_FILE}"
|
21
|
+
task :retrieve do
|
22
|
+
dir = "tmp/readme"
|
23
|
+
rm_rf dir if File.exist?(dir)
|
24
|
+
mkdir_p dir
|
25
|
+
s = File.read(README_FILE, encoding: 'utf-8')
|
26
|
+
filename = nil
|
27
|
+
buf = nil
|
28
|
+
s.each_line do |line|
|
29
|
+
case line
|
30
|
+
when README_EXTRACT
|
31
|
+
filename = $1
|
32
|
+
next
|
33
|
+
when README_CODESTART
|
34
|
+
if filename
|
35
|
+
buf = []
|
36
|
+
end
|
37
|
+
next
|
38
|
+
when README_CODEEND
|
39
|
+
if filename && buf
|
40
|
+
newfile = "#{dir}/#{filename}"
|
41
|
+
unless File.exist?(File.dirname(newfile))
|
42
|
+
mkdir_p File.dirname(newfile)
|
43
|
+
end
|
44
|
+
str = readme_extract_callback(filename, buf.join())
|
45
|
+
File.write(newfile, str, encoding: 'utf-8')
|
46
|
+
puts "[retrieve] #{newfile}"
|
47
|
+
end
|
48
|
+
filename = nil
|
49
|
+
buf = nil
|
50
|
+
next
|
51
|
+
end
|
52
|
+
#
|
53
|
+
if buf
|
54
|
+
buf << line
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "execute code in readme file"
|
60
|
+
task :execute => :retrieve do
|
61
|
+
Dir.glob(README_DESTDIR+'/**/*.rb').sort.each do |fpath|
|
62
|
+
puts "========================================"
|
63
|
+
sh "ruby -I lib #{fpath}" do end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "builds table of contents"
|
68
|
+
task :toc do
|
69
|
+
url = ENV['README_URL'] or abort "$README_URL required."
|
70
|
+
htmlfile = "README.html"
|
71
|
+
sh "curl -s -o #{htmlfile} #{url}"
|
72
|
+
rexp = /<h(\d)><a id="(.*?)" class="anchor".*><\/a>(.*)<\/h\1>/
|
73
|
+
html_str = File.read(htmlfile, encoding: 'utf-8')
|
74
|
+
buf = []
|
75
|
+
html_str.scan(rexp) do
|
76
|
+
level = $1.to_i
|
77
|
+
id = $2
|
78
|
+
title = $3
|
79
|
+
next if title =~ /Table of Contents/
|
80
|
+
anchor = id.sub(/^user-content-/, '')
|
81
|
+
indent = " " * (level - 1)
|
82
|
+
buf << "#{indent}* <a href=\"##{anchor}\">#{title}</a>\n"
|
83
|
+
end
|
84
|
+
buf.shift() if buf[0] && buf[0] =~ /^\* /
|
85
|
+
toc_str = buf.join()
|
86
|
+
#
|
87
|
+
changed = File.open("README.md", "r+", encoding: 'utf-8') do |f|
|
88
|
+
s1 = f.read()
|
89
|
+
s2 = s1.sub(/(<!-- TOC -->\n).*(<!-- \/TOC -->\n)/m) {
|
90
|
+
[$1, toc_str, $2].join("\n")
|
91
|
+
}
|
92
|
+
if s1 != s2
|
93
|
+
f.rewind()
|
94
|
+
f.truncate(0)
|
95
|
+
f.write(s2)
|
96
|
+
true
|
97
|
+
else
|
98
|
+
false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
puts "[changed] README.md" if changed
|
102
|
+
puts "[not changed] README.md" unless changed
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
###
|
4
|
+
### $Release: 1.0.0 $
|
5
|
+
### $Copyright: copyright(c) 2011-2021 kuwata-lab.com all rights reserved $
|
6
|
+
### $License: MIT License $
|
7
|
+
###
|
8
|
+
|
9
|
+
File.class_eval do
|
10
|
+
libpath = join(dirname(dirname(expand_path(__FILE__))), 'lib')
|
11
|
+
$LOAD_PATH.unshift(libpath) unless $LOAD_PATH.include?(libpath)
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'minitest/spec'
|
15
|
+
require 'minitest/autorun'
|
16
|
+
require 'minitest/ok'
|
17
|
+
|
18
|
+
require 'benry/recorder'
|
19
|
+
|
20
|
+
|
21
|
+
class Calc4190
|
22
|
+
def average(*nums) # average() calls total()
|
23
|
+
return total(*nums) / nums.length
|
24
|
+
end
|
25
|
+
def total(*nums)
|
26
|
+
t = 0
|
27
|
+
nums.each {|n| t += n }
|
28
|
+
return t # or return nums.sum
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
describe Benry::Recorder do
|
34
|
+
|
35
|
+
describe '#record_method()' do
|
36
|
+
it "[!61z3j] records method calls." do
|
37
|
+
rec = Benry::Recorder.new
|
38
|
+
calc = Calc4190.new
|
39
|
+
rec.record_method(calc, :total, :average)
|
40
|
+
avg = calc.average(10, 20, 30, 40) #=> 25
|
41
|
+
#
|
42
|
+
ok {rec.length} == 2
|
43
|
+
#
|
44
|
+
ok {rec[0].obj} == calc
|
45
|
+
ok {rec[0].name} == :average
|
46
|
+
ok {rec[0].args} == [10, 20, 30, 40]
|
47
|
+
ok {rec[0].ret} == 25
|
48
|
+
#
|
49
|
+
ok {rec[1].obj} == calc
|
50
|
+
ok {rec[1].name} == :total
|
51
|
+
ok {rec[1].args} == [10, 20, 30, 40]
|
52
|
+
ok {rec[1].ret} == 100
|
53
|
+
end
|
54
|
+
it "[!9kh1f] calls original method." do
|
55
|
+
rec = Benry::Recorder.new
|
56
|
+
calc = Calc4190.new
|
57
|
+
rec.record_method(calc, :total, :average)
|
58
|
+
ok {calc.average(10, 20, 30, 40)} == 25
|
59
|
+
ok {calc.average(1.0, 2.0, 3.0, 4.0)} == 2.5
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#fake_method()' do
|
64
|
+
it "[!g112x] defines fake methods." do
|
65
|
+
rec = Benry::Recorder.new
|
66
|
+
calc = Calc4190.new
|
67
|
+
rec.fake_method(calc, :total=>150)
|
68
|
+
ret = calc.average(10, 20) # calc.average() calls calc.total() internally
|
69
|
+
ok {ret} == 75 # 75 == 150/2
|
70
|
+
#
|
71
|
+
ok {rec.length} == 1
|
72
|
+
ok {rec[0].obj} == calc
|
73
|
+
ok {rec[0].name} == :total
|
74
|
+
ok {rec[0].args} == [10, 20]
|
75
|
+
ok {rec[0].ret} == 150
|
76
|
+
end
|
77
|
+
it "[!kgvm1] defined methods can can take any arguments." do
|
78
|
+
rec = Benry::Recorder.new
|
79
|
+
calc = Calc4190.new
|
80
|
+
rec.fake_method(calc, :total=>999)
|
81
|
+
ret = calc.total(10, 20, :a=>1, 'b'=>2)
|
82
|
+
ok {ret} == 999
|
83
|
+
#
|
84
|
+
ok {rec.length} == 1
|
85
|
+
#
|
86
|
+
ok {rec[0].obj} == calc
|
87
|
+
ok {rec[0].name} == :total
|
88
|
+
ok {rec[0].args} == [10, 20, {:a=>1, 'b'=>2}]
|
89
|
+
ok {rec[0].ret} == 999
|
90
|
+
end
|
91
|
+
it "[!2p1b0] returns self." do
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#fake_object()' do
|
96
|
+
it "[!hympr] creates fake object." do
|
97
|
+
rec = Benry::Recorder.new
|
98
|
+
obj = rec.fake_object(:foo=>123, :bar=>"abc")
|
99
|
+
ok {obj.foo(10, 20, 'a'=>1, 'b'=>2)} == 123
|
100
|
+
ok {obj.bar(30, 40, x: 8, y: 9)} == "abc"
|
101
|
+
#
|
102
|
+
ok {rec.length} == 2
|
103
|
+
#
|
104
|
+
ok {rec[0].obj} == obj
|
105
|
+
ok {rec[0].name} == :foo
|
106
|
+
ok {rec[0].args} == [10, 20, {'a'=>1, 'b'=>2}]
|
107
|
+
ok {rec[0].ret} == 123
|
108
|
+
#
|
109
|
+
ok {rec[1].obj} == obj
|
110
|
+
ok {rec[1].name} == :bar
|
111
|
+
ok {rec[1].args} == [30, 40, {:x=>8, :y=>9}]
|
112
|
+
ok {rec[1].ret} == "abc"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#inspect()' do
|
117
|
+
it "[!k85bz] represents internal data." do
|
118
|
+
rec = Benry::Recorder.new
|
119
|
+
calc = Calc4190.new
|
120
|
+
rec.fake_method(calc, :total=>200)
|
121
|
+
rec.record_method(calc, :average)
|
122
|
+
ret = calc.average(10, 20, 30, 40)
|
123
|
+
#
|
124
|
+
s = rec.inspect.gsub(/#<Calc4190:0x\w+>/, '#<Calc4190:0xXXXX>')
|
125
|
+
ok {s} == ("0: #<Calc4190:0xXXXX>.average(10, 20, 30, 40) #=> 50\n"\
|
126
|
+
"1: #<Calc4190:0xXXXX>.total(10, 20, 30, 40) #=> 200\n")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
describe Benry::Recorder::Called do
|
134
|
+
|
135
|
+
before do
|
136
|
+
@calc = Calc4190.new
|
137
|
+
@rec = Benry::Recorder.new
|
138
|
+
@rec.record_method(@calc, :total, :average)
|
139
|
+
avg = @calc.average(10, 20, 30, 40) #=> 25
|
140
|
+
@called0 = @rec[0]
|
141
|
+
@called1 = @rec[1]
|
142
|
+
end
|
143
|
+
|
144
|
+
describe '#obj' do
|
145
|
+
it "[!m98p9] returns receiver object." do
|
146
|
+
ok {@called0.obj} == @calc
|
147
|
+
ok {@called1.obj} == @calc
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#name' do
|
152
|
+
it "[!es61g] returns method name." do
|
153
|
+
ok {@called0.name} == :average
|
154
|
+
ok {@called1.name} == :total
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe '#args' do
|
159
|
+
it "[!2yeeo] returns arguments." do
|
160
|
+
ok {@called0.args} == [10, 20, 30, 40]
|
161
|
+
ok {@called1.args} == [10, 20, 30, 40]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#ret' do
|
166
|
+
it "[!yd3hl] returns arguments." do
|
167
|
+
ok {@called0.ret} == 25
|
168
|
+
ok {@called1.ret} == 100
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe '#to_a' do
|
173
|
+
it "[!hrol9] returns array of obj, nae, args, and ret." do
|
174
|
+
ok {@called0.to_a} == [@calc, :average, [10, 20, 30, 40], 25]
|
175
|
+
ok {@called1.to_a} == [@calc, :total, [10, 20, 30, 40], 100]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe '#inspect()' do
|
180
|
+
it "[!g2iwe] represents internal data." do
|
181
|
+
rexp = /\A#<Calc4190:0x\w+>\.average\(10, 20, 30, 40\) #=> 25\z/
|
182
|
+
ok {@called0.inspect()} =~ rexp
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
data/test/run_all.rb
ADDED
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: benry-recorder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kwatch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-08-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest-ok
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: |
|
42
|
+
Benry-recorder is a tiny utility that can:
|
43
|
+
|
44
|
+
* Record method calls of target object.
|
45
|
+
* Define fake methods on target object.
|
46
|
+
* Create fake object which has fake methods.
|
47
|
+
email: kwatch@gmail.com
|
48
|
+
executables: []
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
files:
|
52
|
+
- README.md
|
53
|
+
- Rakefile.rb
|
54
|
+
- benry-recorder.gemspec
|
55
|
+
- lib/benry/recorder.rb
|
56
|
+
- task/common-task.rb
|
57
|
+
- task/readme-task.rb
|
58
|
+
- test/recorder_test.rb
|
59
|
+
- test/run_all.rb
|
60
|
+
homepage: https://github.com/kwatch/benry-ruby/tree/ruby/benry-recorder
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.5.2.3
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: Record method calls, or define fake methods.
|
84
|
+
test_files:
|
85
|
+
- test/recorder_test.rb
|