royw-read_page_cache 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.rdoc +43 -0
- data/Rakefile +48 -0
- data/VERSION.yml +4 -0
- data/lib/file_extensions.rb +18 -0
- data/lib/module_extensions.rb +27 -0
- data/lib/read_page_cache.rb +89 -0
- data/spec/read_page_cache_spec.rb +85 -0
- data/spec/spec_helper.rb +9 -0
- metadata +63 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2009 Roy Wright
|
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 NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
= read_page_cache
|
2
|
+
|
3
|
+
== Synopsis
|
4
|
+
The purpose of the module is to cache web pages used for testing by overriding
|
5
|
+
the classes' read_page method and replacing it with one that will cache pages.
|
6
|
+
|
7
|
+
== Usage
|
8
|
+
Your main code needs to have a read_page(page) instance method(s). Here's an
|
9
|
+
example:
|
10
|
+
|
11
|
+
class ClassName
|
12
|
+
def read_page(page)
|
13
|
+
open(page).read
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Then your test code should include:
|
18
|
+
|
19
|
+
# default directory is '/tmp'
|
20
|
+
directory = '/path/to/cache/files'
|
21
|
+
|
22
|
+
require 'cache_extensions'
|
23
|
+
ReadPageCache.attach_to ClassName, directory
|
24
|
+
|
25
|
+
You may attach_to however many classes that you need to.
|
26
|
+
|
27
|
+
If you want to override all the read_page(page) methods in your application,
|
28
|
+
then your test code can instead use:
|
29
|
+
|
30
|
+
# default directory is '/tmp'
|
31
|
+
directory = '/path/to/cache/files'
|
32
|
+
|
33
|
+
require 'cache_extensions'
|
34
|
+
ReadPageCache.attach_to_classes directory
|
35
|
+
|
36
|
+
That's it. The first time you run your tests, the web pages your application
|
37
|
+
accesses with read_page will be cached, then the cached files will be used by
|
38
|
+
all subsequent accesses. You may want to review the cache and add any files
|
39
|
+
you want to your version control system.
|
40
|
+
|
41
|
+
== Copyright
|
42
|
+
|
43
|
+
Copyright (c) 2009 Roy Wright. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "read_page_cache"
|
8
|
+
gem.summary = %Q{TODO}
|
9
|
+
gem.email = "roy@wright.org"
|
10
|
+
gem.homepage = "http://github.com/royw/read_page_cache"
|
11
|
+
gem.authors = ["Roy Wright"]
|
12
|
+
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'spec/rake/spectask'
|
20
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
21
|
+
spec.libs << 'lib' << 'spec'
|
22
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
23
|
+
end
|
24
|
+
|
25
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
26
|
+
spec.libs << 'lib' << 'spec'
|
27
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
28
|
+
spec.rcov = true
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task :default => :spec
|
33
|
+
|
34
|
+
require 'rake/rdoctask'
|
35
|
+
Rake::RDocTask.new do |rdoc|
|
36
|
+
if File.exist?('VERSION.yml')
|
37
|
+
config = YAML.load(File.read('VERSION.yml'))
|
38
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
39
|
+
else
|
40
|
+
version = ""
|
41
|
+
end
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "read_page_cache #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
48
|
+
|
data/VERSION.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# == Synopsis
|
2
|
+
# add a mkdirs method to the File class
|
3
|
+
class File
|
4
|
+
class << self
|
5
|
+
my_extension("mkdirs") do
|
6
|
+
##
|
7
|
+
# make directories including any missing in the path
|
8
|
+
#
|
9
|
+
# @param [String] dirspec the path to make sure exists
|
10
|
+
def File.mkdirs(dirspec)
|
11
|
+
unless File.exists?(dirspec)
|
12
|
+
mkdirs(File.dirname(dirspec))
|
13
|
+
Dir.mkdir(dirspec)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
######################################################################
|
2
|
+
# my extensions to Module. (taken from rake, named changed to not clash
|
3
|
+
# when rake is used for this rails project.
|
4
|
+
#
|
5
|
+
class Module
|
6
|
+
# Check for an existing method in the current class before extending. IF
|
7
|
+
# the method already exists, then a warning is printed and the extension is
|
8
|
+
# not added. Otherwise the block is yielded and any definitions in the
|
9
|
+
# block will take effect.
|
10
|
+
#
|
11
|
+
# Usage:
|
12
|
+
#
|
13
|
+
# class String
|
14
|
+
# rake_extension("xyz") do
|
15
|
+
# def xyz
|
16
|
+
# ...
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
def my_extension(method)
|
22
|
+
unless instance_methods.include?(method.to_s) || instance_methods.include?(method.to_sym)
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end # module Module
|
27
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'module_extensions'
|
2
|
+
require 'file_extensions'
|
3
|
+
|
4
|
+
# == Synopsis
|
5
|
+
# The purpose of the module is to cache web pages used for
|
6
|
+
# testing by overriding the classes' read_page method and
|
7
|
+
# replacing it with one that will cache pages.
|
8
|
+
#
|
9
|
+
# == Usage
|
10
|
+
# Your main code needs to have a read_page(page) instance
|
11
|
+
# method(s). Here's an example:
|
12
|
+
#
|
13
|
+
# class ClassName
|
14
|
+
# def read_page(page)
|
15
|
+
# open(page).read
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Then your test code should include:
|
20
|
+
#
|
21
|
+
# # default directory is '/tmp'
|
22
|
+
# directory = '/path/to/cache/files'
|
23
|
+
# require 'cache_extensions'
|
24
|
+
# ReadPageCache.attach_to ClassName, directory
|
25
|
+
#
|
26
|
+
# You may attach_to however many classes that you need to.
|
27
|
+
#
|
28
|
+
# If you want to override all the read_page(page) methods
|
29
|
+
# in your application, then your test code can instead use:
|
30
|
+
#
|
31
|
+
# # default directory is '/tmp'
|
32
|
+
# directory = '/path/to/cache/files'
|
33
|
+
# require 'cache_extensions'
|
34
|
+
# ReadPageCache.attach_to_classes directory
|
35
|
+
#
|
36
|
+
# That's it. The first time you run your tests, the pages
|
37
|
+
# your application accesses with read_page will be cached,
|
38
|
+
# then the cached files will be used by all subsequent accesses.
|
39
|
+
#
|
40
|
+
module ReadPageCache
|
41
|
+
# == Synopsis
|
42
|
+
# Attach the read_page and cache_file methods to the given
|
43
|
+
# class (cls) and use the given directory for the cache files
|
44
|
+
def self.attach_to(cls, directory='/tmp')
|
45
|
+
|
46
|
+
# define the read_page(page) method on the given class: cls
|
47
|
+
cls.send('define_method', "read_page") do |page|
|
48
|
+
data = nil
|
49
|
+
filespec = page.gsub(/^http:\//, directory).gsub(/\/$/, '.html')
|
50
|
+
if File.exist?(filespec)
|
51
|
+
data = open(filespec).read
|
52
|
+
else
|
53
|
+
data = open(page).read
|
54
|
+
_cache_file(page, data)
|
55
|
+
end
|
56
|
+
data
|
57
|
+
end
|
58
|
+
|
59
|
+
# define the cache_file(page, data) method on the given class: cls
|
60
|
+
cls.send('define_method', "_cache_file") do |page, data|
|
61
|
+
begin
|
62
|
+
filespec = page.gsub(/^http:\//, directory).gsub(/\/$/, '.html')
|
63
|
+
unless File.exist?(filespec)
|
64
|
+
puts "caching #{filespec}"
|
65
|
+
File.mkdirs(File.dirname(filespec))
|
66
|
+
File.open(filespec, 'w') { |f| f.puts data }
|
67
|
+
end
|
68
|
+
rescue Exception => eMsg
|
69
|
+
puts eMsg.to_s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# == Synopsis
|
75
|
+
# Find all classes that have a read_page instance method and
|
76
|
+
# then overwrite that read_page method with one that handles
|
77
|
+
# the caching. Use the given directory for the cache files.
|
78
|
+
def self.attach_to_classes(directory='/tmp')
|
79
|
+
ObjectSpace.each_object(Class) do |cls|
|
80
|
+
# need to check all scopes for read_page instance method
|
81
|
+
if(cls.public_instance_methods(false).include?("read_page") ||
|
82
|
+
cls.protected_instance_methods(false).include?("read_page") ||
|
83
|
+
cls.private_instance_methods(false).include?("read_page"))
|
84
|
+
ReadPageCache.attach_to(cls, directory)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ruby-debug'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
TMPDIR = File.join(File.dirname(__FILE__), '../tmp')
|
6
|
+
Dir.mkdir(TMPDIR) unless File.exist?(TMPDIR)
|
7
|
+
|
8
|
+
TEST_DATA = "Testing cache read"
|
9
|
+
|
10
|
+
describe "ReadPageCache" do
|
11
|
+
|
12
|
+
after(:each) do
|
13
|
+
Dir.glob(File.join(TMPDIR, '*')).each {|f| File.delete(f) if File.exist?(f)}
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should add read_page method to a class' do
|
17
|
+
class A
|
18
|
+
end
|
19
|
+
# attach to the class then create instance
|
20
|
+
ReadPageCache.attach_to A, TMPDIR
|
21
|
+
a = A.new
|
22
|
+
a.respond_to?('read_page').should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should add read_page method to a class not the instance' do
|
26
|
+
class A
|
27
|
+
end
|
28
|
+
# create instance then attach to the class
|
29
|
+
a = A.new
|
30
|
+
ReadPageCache.attach_to A, TMPDIR
|
31
|
+
a.respond_to?('read_page').should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
# this is not nice but we make a web access to www.example.com
|
35
|
+
# just to get a response to cache. There probably is a better
|
36
|
+
# website to do this to.
|
37
|
+
it 'should override the read_page method in a class' do
|
38
|
+
class A
|
39
|
+
def read_page(page)
|
40
|
+
open(page).read
|
41
|
+
end
|
42
|
+
end
|
43
|
+
ReadPageCache.attach_to A, TMPDIR
|
44
|
+
a = A.new
|
45
|
+
a.read_page('http://www.example.com/')
|
46
|
+
filespec = File.join(TMPDIR, 'www.example.com.html')
|
47
|
+
(File.exist?(filespec).should be_true) && (File.size(filespec).should > 0)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should read from the cache' do
|
51
|
+
filespec = File.join(TMPDIR, 'www.example.com.html')
|
52
|
+
File.open(filespec, "w") {|f| f.puts TEST_DATA}
|
53
|
+
|
54
|
+
class A
|
55
|
+
def read_page(page)
|
56
|
+
open(page).read
|
57
|
+
end
|
58
|
+
end
|
59
|
+
ReadPageCache.attach_to A, TMPDIR
|
60
|
+
a = A.new
|
61
|
+
data = a.read_page('http://www.example.com/').strip
|
62
|
+
data.should == TEST_DATA
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should replace all read_page methods in all classes' do
|
66
|
+
# create two classes with read_page methods
|
67
|
+
class A
|
68
|
+
def read_page(page)
|
69
|
+
open(page).read
|
70
|
+
end
|
71
|
+
end
|
72
|
+
class B
|
73
|
+
def read_page(page)
|
74
|
+
open(page).read
|
75
|
+
end
|
76
|
+
end
|
77
|
+
# when we attach to the class, ReadPageCache also puts a _cache_file method
|
78
|
+
# into the class, so we can simply test for it's presence.
|
79
|
+
ReadPageCache.attach_to_classes(TMPDIR)
|
80
|
+
a = A.new
|
81
|
+
b = B.new
|
82
|
+
(a.respond_to?('_cache_file').should be_true) && (b.respond_to?('_cache_file').should be_true)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: royw-read_page_cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Roy Wright
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-20 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: roy@wright.org
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- VERSION.yml
|
30
|
+
- lib/file_extensions.rb
|
31
|
+
- lib/module_extensions.rb
|
32
|
+
- lib/read_page_cache.rb
|
33
|
+
- spec/read_page_cache_spec.rb
|
34
|
+
- spec/spec_helper.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/royw/read_page_cache
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options:
|
39
|
+
- --charset=UTF-8
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.2.0
|
58
|
+
signing_key:
|
59
|
+
specification_version: 2
|
60
|
+
summary: TODO
|
61
|
+
test_files:
|
62
|
+
- spec/spec_helper.rb
|
63
|
+
- spec/read_page_cache_spec.rb
|