wayfarer 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rbenv-gemsets +1 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +21 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +5 -0
  8. data/.yardopts +3 -0
  9. data/Changelog.md +10 -0
  10. data/Gemfile +11 -0
  11. data/LICENSE +19 -0
  12. data/README.md +21 -0
  13. data/Rakefile +114 -0
  14. data/benchmark/frontiers.rb +143 -0
  15. data/bin/wayfarer +116 -0
  16. data/docs/.gitignore +2 -0
  17. data/docs/_config.yml +15 -0
  18. data/docs/_includes/base.html +7 -0
  19. data/docs/_includes/head.html +10 -0
  20. data/docs/_includes/navigation.html +187 -0
  21. data/docs/_layouts/default.html +42 -0
  22. data/docs/_sass/base.scss +439 -0
  23. data/docs/_sass/variables.scss +24 -0
  24. data/docs/_sass/vendor/bourbon/_bourbon-deprecate.scss +19 -0
  25. data/docs/_sass/vendor/bourbon/_bourbon-deprecated-upcoming.scss +425 -0
  26. data/docs/_sass/vendor/bourbon/_bourbon.scss +90 -0
  27. data/docs/_sass/vendor/bourbon/addons/_border-color.scss +29 -0
  28. data/docs/_sass/vendor/bourbon/addons/_border-radius.scss +48 -0
  29. data/docs/_sass/vendor/bourbon/addons/_border-style.scss +28 -0
  30. data/docs/_sass/vendor/bourbon/addons/_border-width.scss +28 -0
  31. data/docs/_sass/vendor/bourbon/addons/_buttons.scss +69 -0
  32. data/docs/_sass/vendor/bourbon/addons/_clearfix.scss +25 -0
  33. data/docs/_sass/vendor/bourbon/addons/_ellipsis.scss +30 -0
  34. data/docs/_sass/vendor/bourbon/addons/_font-stacks.scss +31 -0
  35. data/docs/_sass/vendor/bourbon/addons/_hide-text.scss +27 -0
  36. data/docs/_sass/vendor/bourbon/addons/_margin.scss +29 -0
  37. data/docs/_sass/vendor/bourbon/addons/_padding.scss +29 -0
  38. data/docs/_sass/vendor/bourbon/addons/_position.scss +51 -0
  39. data/docs/_sass/vendor/bourbon/addons/_prefixer.scss +66 -0
  40. data/docs/_sass/vendor/bourbon/addons/_retina-image.scss +27 -0
  41. data/docs/_sass/vendor/bourbon/addons/_size.scss +56 -0
  42. data/docs/_sass/vendor/bourbon/addons/_text-inputs.scss +118 -0
  43. data/docs/_sass/vendor/bourbon/addons/_timing-functions.scss +34 -0
  44. data/docs/_sass/vendor/bourbon/addons/_triangle.scss +63 -0
  45. data/docs/_sass/vendor/bourbon/addons/_word-wrap.scss +29 -0
  46. data/docs/_sass/vendor/bourbon/css3/_animation.scss +61 -0
  47. data/docs/_sass/vendor/bourbon/css3/_appearance.scss +5 -0
  48. data/docs/_sass/vendor/bourbon/css3/_backface-visibility.scss +5 -0
  49. data/docs/_sass/vendor/bourbon/css3/_background-image.scss +44 -0
  50. data/docs/_sass/vendor/bourbon/css3/_background.scss +57 -0
  51. data/docs/_sass/vendor/bourbon/css3/_border-image.scss +61 -0
  52. data/docs/_sass/vendor/bourbon/css3/_calc.scss +6 -0
  53. data/docs/_sass/vendor/bourbon/css3/_columns.scss +67 -0
  54. data/docs/_sass/vendor/bourbon/css3/_filter.scss +6 -0
  55. data/docs/_sass/vendor/bourbon/css3/_flex-box.scss +327 -0
  56. data/docs/_sass/vendor/bourbon/css3/_font-face.scss +29 -0
  57. data/docs/_sass/vendor/bourbon/css3/_font-feature-settings.scss +6 -0
  58. data/docs/_sass/vendor/bourbon/css3/_hidpi-media-query.scss +12 -0
  59. data/docs/_sass/vendor/bourbon/css3/_hyphens.scss +6 -0
  60. data/docs/_sass/vendor/bourbon/css3/_image-rendering.scss +15 -0
  61. data/docs/_sass/vendor/bourbon/css3/_keyframes.scss +38 -0
  62. data/docs/_sass/vendor/bourbon/css3/_linear-gradient.scss +40 -0
  63. data/docs/_sass/vendor/bourbon/css3/_perspective.scss +12 -0
  64. data/docs/_sass/vendor/bourbon/css3/_placeholder.scss +10 -0
  65. data/docs/_sass/vendor/bourbon/css3/_radial-gradient.scss +40 -0
  66. data/docs/_sass/vendor/bourbon/css3/_selection.scss +44 -0
  67. data/docs/_sass/vendor/bourbon/css3/_text-decoration.scss +27 -0
  68. data/docs/_sass/vendor/bourbon/css3/_transform.scss +21 -0
  69. data/docs/_sass/vendor/bourbon/css3/_transition.scss +81 -0
  70. data/docs/_sass/vendor/bourbon/css3/_user-select.scss +5 -0
  71. data/docs/_sass/vendor/bourbon/functions/_assign-inputs.scss +16 -0
  72. data/docs/_sass/vendor/bourbon/functions/_contains-falsy.scss +25 -0
  73. data/docs/_sass/vendor/bourbon/functions/_contains.scss +31 -0
  74. data/docs/_sass/vendor/bourbon/functions/_is-length.scss +16 -0
  75. data/docs/_sass/vendor/bourbon/functions/_is-light.scss +26 -0
  76. data/docs/_sass/vendor/bourbon/functions/_is-number.scss +16 -0
  77. data/docs/_sass/vendor/bourbon/functions/_is-size.scss +23 -0
  78. data/docs/_sass/vendor/bourbon/functions/_modular-scale.scss +74 -0
  79. data/docs/_sass/vendor/bourbon/functions/_px-to-em.scss +24 -0
  80. data/docs/_sass/vendor/bourbon/functions/_px-to-rem.scss +26 -0
  81. data/docs/_sass/vendor/bourbon/functions/_shade.scss +24 -0
  82. data/docs/_sass/vendor/bourbon/functions/_strip-units.scss +22 -0
  83. data/docs/_sass/vendor/bourbon/functions/_tint.scss +24 -0
  84. data/docs/_sass/vendor/bourbon/functions/_transition-property-name.scss +37 -0
  85. data/docs/_sass/vendor/bourbon/functions/_unpack.scss +32 -0
  86. data/docs/_sass/vendor/bourbon/helpers/_convert-units.scss +26 -0
  87. data/docs/_sass/vendor/bourbon/helpers/_directional-values.scss +108 -0
  88. data/docs/_sass/vendor/bourbon/helpers/_font-source-declaration.scss +53 -0
  89. data/docs/_sass/vendor/bourbon/helpers/_gradient-positions-parser.scss +24 -0
  90. data/docs/_sass/vendor/bourbon/helpers/_linear-angle-parser.scss +35 -0
  91. data/docs/_sass/vendor/bourbon/helpers/_linear-gradient-parser.scss +51 -0
  92. data/docs/_sass/vendor/bourbon/helpers/_linear-positions-parser.scss +77 -0
  93. data/docs/_sass/vendor/bourbon/helpers/_linear-side-corner-parser.scss +41 -0
  94. data/docs/_sass/vendor/bourbon/helpers/_radial-arg-parser.scss +74 -0
  95. data/docs/_sass/vendor/bourbon/helpers/_radial-gradient-parser.scss +55 -0
  96. data/docs/_sass/vendor/bourbon/helpers/_radial-positions-parser.scss +28 -0
  97. data/docs/_sass/vendor/bourbon/helpers/_render-gradients.scss +31 -0
  98. data/docs/_sass/vendor/bourbon/helpers/_shape-size-stripper.scss +15 -0
  99. data/docs/_sass/vendor/bourbon/helpers/_str-to-num.scss +55 -0
  100. data/docs/_sass/vendor/bourbon/settings/_asset-pipeline.scss +7 -0
  101. data/docs/_sass/vendor/bourbon/settings/_deprecation-warnings.scss +8 -0
  102. data/docs/_sass/vendor/bourbon/settings/_prefixer.scss +9 -0
  103. data/docs/_sass/vendor/bourbon/settings/_px-to-em.scss +1 -0
  104. data/docs/_sass/vendor/neat/_neat-helpers.scss +11 -0
  105. data/docs/_sass/vendor/neat/_neat.scss +23 -0
  106. data/docs/_sass/vendor/neat/functions/_new-breakpoint.scss +49 -0
  107. data/docs/_sass/vendor/neat/functions/_private.scss +114 -0
  108. data/docs/_sass/vendor/neat/grid/_box-sizing.scss +15 -0
  109. data/docs/_sass/vendor/neat/grid/_direction-context.scss +33 -0
  110. data/docs/_sass/vendor/neat/grid/_display-context.scss +28 -0
  111. data/docs/_sass/vendor/neat/grid/_fill-parent.scss +22 -0
  112. data/docs/_sass/vendor/neat/grid/_media.scss +92 -0
  113. data/docs/_sass/vendor/neat/grid/_omega.scss +87 -0
  114. data/docs/_sass/vendor/neat/grid/_outer-container.scss +34 -0
  115. data/docs/_sass/vendor/neat/grid/_pad.scss +25 -0
  116. data/docs/_sass/vendor/neat/grid/_private.scss +35 -0
  117. data/docs/_sass/vendor/neat/grid/_row.scss +52 -0
  118. data/docs/_sass/vendor/neat/grid/_shift.scss +50 -0
  119. data/docs/_sass/vendor/neat/grid/_span-columns.scss +94 -0
  120. data/docs/_sass/vendor/neat/grid/_to-deprecate.scss +97 -0
  121. data/docs/_sass/vendor/neat/grid/_visual-grid.scss +42 -0
  122. data/docs/_sass/vendor/neat/mixins/_clearfix.scss +25 -0
  123. data/docs/_sass/vendor/neat/settings/_disable-warnings.scss +13 -0
  124. data/docs/_sass/vendor/neat/settings/_grid.scss +51 -0
  125. data/docs/_sass/vendor/neat/settings/_visual-grid.scss +27 -0
  126. data/docs/_sass/vendor/normalize-3.0.2.scss +427 -0
  127. data/docs/_sass/vendor/pygments.scss +356 -0
  128. data/docs/automating_browsers/capybara.md +70 -0
  129. data/docs/css/screen.scss +7 -0
  130. data/docs/guides/callbacks.md +45 -0
  131. data/docs/guides/cli.md +52 -0
  132. data/docs/guides/configuration.md +184 -0
  133. data/docs/guides/error_handling.md +46 -0
  134. data/docs/guides/frontiers.md +93 -0
  135. data/docs/guides/halting.md +23 -0
  136. data/docs/guides/job_queues.md +26 -0
  137. data/docs/guides/locals.md +36 -0
  138. data/docs/guides/logging.md +22 -0
  139. data/docs/guides/page_objects.md +67 -0
  140. data/docs/guides/peeking.md +46 -0
  141. data/docs/guides/selenium_capybara.md +100 -0
  142. data/docs/guides/tutorial.md +452 -0
  143. data/docs/index.md +82 -0
  144. data/docs/js/navigation.js +11 -0
  145. data/docs/misc/contributing.md +20 -0
  146. data/docs/misc/testing.md +11 -0
  147. data/docs/recipes/authentication.md +23 -0
  148. data/docs/recipes/csv.md +29 -0
  149. data/docs/recipes/javascript.md +20 -0
  150. data/docs/recipes/multiple_uris.md +18 -0
  151. data/docs/recipes/screenshots.md +20 -0
  152. data/docs/routing/custom_rules.md +16 -0
  153. data/docs/routing/filetypes_rules.md +21 -0
  154. data/docs/routing/host_rules.md +24 -0
  155. data/docs/routing/path_rules.md +33 -0
  156. data/docs/routing/protocol_rules.md +17 -0
  157. data/docs/routing/query_rules.md +69 -0
  158. data/docs/routing/routes.md +96 -0
  159. data/docs/routing/uri_rules.md +18 -0
  160. data/examples/collect_github_issues.rb +65 -0
  161. data/examples/find_foobar_on_wikipedia.rb +23 -0
  162. data/lib/wayfarer/configuration.rb +86 -0
  163. data/lib/wayfarer/crawl.rb +79 -0
  164. data/lib/wayfarer/crawl_observer.rb +103 -0
  165. data/lib/wayfarer/dispatcher.rb +104 -0
  166. data/lib/wayfarer/finders.rb +61 -0
  167. data/lib/wayfarer/frontiers/frontier.rb +79 -0
  168. data/lib/wayfarer/frontiers/memory_bloomfilter.rb +32 -0
  169. data/lib/wayfarer/frontiers/memory_frontier.rb +76 -0
  170. data/lib/wayfarer/frontiers/memory_trie_frontier.rb +39 -0
  171. data/lib/wayfarer/frontiers/normalize_uris.rb +48 -0
  172. data/lib/wayfarer/frontiers/redis_bloomfilter.rb +34 -0
  173. data/lib/wayfarer/frontiers/redis_frontier.rb +83 -0
  174. data/lib/wayfarer/http_adapters/adapter_pool.rb +62 -0
  175. data/lib/wayfarer/http_adapters/net_http_adapter.rb +77 -0
  176. data/lib/wayfarer/http_adapters/selenium_adapter.rb +80 -0
  177. data/lib/wayfarer/job.rb +211 -0
  178. data/lib/wayfarer/locals.rb +40 -0
  179. data/lib/wayfarer/page.rb +94 -0
  180. data/lib/wayfarer/parsers/json_parser.rb +20 -0
  181. data/lib/wayfarer/parsers/xml_parser.rb +27 -0
  182. data/lib/wayfarer/processor.rb +103 -0
  183. data/lib/wayfarer/routing/custom_rule.rb +21 -0
  184. data/lib/wayfarer/routing/filetypes_rule.rb +20 -0
  185. data/lib/wayfarer/routing/host_rule.rb +19 -0
  186. data/lib/wayfarer/routing/path_rule.rb +54 -0
  187. data/lib/wayfarer/routing/protocol_rule.rb +21 -0
  188. data/lib/wayfarer/routing/query_rule.rb +59 -0
  189. data/lib/wayfarer/routing/router.rb +71 -0
  190. data/lib/wayfarer/routing/rule.rb +114 -0
  191. data/lib/wayfarer/routing/uri_rule.rb +21 -0
  192. data/lib/wayfarer.rb +68 -0
  193. data/spec/configuration_spec.rb +26 -0
  194. data/spec/crawl_spec.rb +48 -0
  195. data/spec/finders_spec.rb +49 -0
  196. data/spec/frontiers/memory_bloomfilter_spec.rb +6 -0
  197. data/spec/frontiers/memory_frontier_spec.rb +6 -0
  198. data/spec/frontiers/memory_trie_frontier_spec.rb +6 -0
  199. data/spec/frontiers/normalize_uris_spec.rb +59 -0
  200. data/spec/frontiers/redis_bloomfilter_spec.rb +6 -0
  201. data/spec/frontiers/redis_frontier_spec.rb +6 -0
  202. data/spec/http_adapters/adapter_pool_spec.rb +33 -0
  203. data/spec/http_adapters/net_http_adapter_spec.rb +83 -0
  204. data/spec/http_adapters/selenium_adapter_spec.rb +53 -0
  205. data/spec/integration/callbacks_spec.rb +42 -0
  206. data/spec/integration/locals_spec.rb +106 -0
  207. data/spec/integration/peeking_spec.rb +61 -0
  208. data/spec/job_spec.rb +122 -0
  209. data/spec/page_spec.rb +38 -0
  210. data/spec/parsers/json_parser_spec.rb +30 -0
  211. data/spec/parsers/xml_parser_spec.rb +24 -0
  212. data/spec/processor_spec.rb +31 -0
  213. data/spec/routing/custom_rule_spec.rb +26 -0
  214. data/spec/routing/filetypes_rule_spec.rb +40 -0
  215. data/spec/routing/host_rule_spec.rb +48 -0
  216. data/spec/routing/path_rule_spec.rb +66 -0
  217. data/spec/routing/protocol_rule_spec.rb +26 -0
  218. data/spec/routing/query_rule_spec.rb +124 -0
  219. data/spec/routing/router_spec.rb +67 -0
  220. data/spec/routing/rule_spec.rb +251 -0
  221. data/spec/routing/uri_rule_spec.rb +24 -0
  222. data/spec/shared/frontier.rb +96 -0
  223. data/spec/spec_helpers.rb +62 -0
  224. data/spec/wayfarer_spec.rb +24 -0
  225. data/support/static/finders.html +38 -0
  226. data/support/static/graph/details/a.html +10 -0
  227. data/support/static/graph/details/b.html +10 -0
  228. data/support/static/graph/index.html +20 -0
  229. data/support/static/json/dummy.json +13 -0
  230. data/support/static/links/links.html +28 -0
  231. data/support/static/xml/dummy.xml +120 -0
  232. data/support/test_app.rb +45 -0
  233. data/wayfarer-jruby.gemspec +49 -0
  234. data/wayfarer.gemspec +53 -0
  235. metadata +697 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c99ff804578236db96766eecce89450d6e489f4d
4
+ data.tar.gz: 8340d4c0e55cb35c20fc688f6ac9badfb6b4a6cc
5
+ SHA512:
6
+ metadata.gz: 10308569f8290771a7fce4e5b382c19103cd29671d539fc85917852e6194722ee9b8c8d49f08bc8034bf63f604b13a369fdfffb69ed67703ec3c2ca25d490352
7
+ data.tar.gz: 2726271b256bab8781267dd6851ba0fda6601fea2fae38f3ed7adf68c0ba64190d3da0fcb38cf4bc0de39a7c3ddfe3507c32714a2fbcc5fbf813659dbe0459bc
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ .DS_Store
2
+ .bundle
3
+ .yardoc
4
+ Gemfile.lock
5
+ *.gem
6
+ build/
7
+ bench/
8
+ yard/
data/.rbenv-gemsets ADDED
@@ -0,0 +1 @@
1
+ wayfarer
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --tty
data/.rubocop.yml ADDED
@@ -0,0 +1,21 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "spec/**/*"
4
+ - "examples/**/*"
5
+ - "support/**/*"
6
+ - "wayfarer.gemspec"
7
+ - "examples"
8
+
9
+ Style/StringLiterals:
10
+ EnforcedStyle: double_quotes
11
+
12
+ Style/BlockDelimiters:
13
+ EnforcedStyle: semantic
14
+ FunctionalMethods:
15
+ - expect
16
+
17
+ Metrics/MethodLength:
18
+ Max: 25
19
+
20
+ Metrics/PerceivedComplexity:
21
+ Max: 10
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.1
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ services: redis-server
3
+ rvm:
4
+ - 2.3.1
5
+ - jruby-9.1.6.0
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --output-dir yard
2
+ --markup markdown
3
+ --protected
data/Changelog.md ADDED
@@ -0,0 +1,10 @@
1
+ ## 0.0.2
2
+
3
+ Features:
4
+
5
+ * `Job#stage` now expands relative paths/URIs
6
+ * Added `ProtocolRule` and `CustomRule`
7
+
8
+ Bugfixes:
9
+
10
+ * Fixed the CLI which relied on a removed method alias
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "github-pages", group: :jekyll_plugins
6
+
7
+ gemspec name: if RUBY_PLATFORM == "java"
8
+ "wayfarer-jruby"
9
+ else
10
+ "wayfarer"
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2017 Dominic Bauer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # Wayfarer
2
+ [![Build Status](https://travis-ci.org/bauerd/wayfarer.svg)](https://travis-ci.org/bauerd/wayfarer)
3
+ [![Code Climate](https://codeclimate.com/github/bauerd/wayfarer/badges/gpa.svg)](https://codeclimate.com/github/bauerd/wayfarer)
4
+
5
+ Versatile web crawling with (J)Ruby
6
+
7
+ * [__Usage and more__ on the website](https://bauerd.github.io/wayfarer/)
8
+ * [__API documentation__ on Ruby-Doc.org](http://www.rubydoc.info/github/bauerd/wayfarer) (`master` branch)
9
+ * __Releases__ on RubyGems.org:
10
+ * [wayfarer](https://rubygems.org/gems/wayfarer)
11
+ * [wayfarer-jruby](https://rubygems.org/gems/wayfarer-jruby)
12
+
13
+ MRI:
14
+ ```
15
+ % [sudo] gem install wayfarer
16
+ ```
17
+
18
+ JRuby:
19
+ ```
20
+ % [sudo] gem install wayfarer-jruby
21
+ ```
data/Rakefile ADDED
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/core/rake_task"
4
+ require "rubocop/rake_task"
5
+ require "rack"
6
+
7
+ require_relative "support/test_app"
8
+
9
+ task default: ["ci"]
10
+
11
+ namespace :test do
12
+ desc "Run only environment-agnostic tests"
13
+ RSpec::Core::RakeTask.new isolated: [:test_app] do |task|
14
+ task.rspec_opts = ["--tag ~selenium --tag ~redis"]
15
+ end
16
+
17
+ desc "Run only integration tests"
18
+ RSpec::Core::RakeTask.new integration: [:test_app] do |task|
19
+ task.rspec_opts = ["--tag integration"]
20
+ end
21
+
22
+ desc "Run only Selenium tests"
23
+ RSpec::Core::RakeTask.new selenium: [:test_app] do |task|
24
+ task.rspec_opts = ["--tag selenium"]
25
+ end
26
+
27
+ desc "Run only Redis tests"
28
+ RSpec::Core::RakeTask.new redis: [:test_app] do |task|
29
+ task.rspec_opts = ["--tag redis"]
30
+ end
31
+ end
32
+
33
+ desc "Run all tests"
34
+ RSpec::Core::RakeTask.new(test: :test_app)
35
+
36
+ RuboCop::RakeTask.new do |task|
37
+ task.formatters = ["simple"]
38
+ end
39
+
40
+ desc "Run benchmarks"
41
+ task :benchmark do
42
+ bms = Rake::FileList["benchmark/*.rb"]
43
+
44
+ bms.each do |bm|
45
+ sh "bundle exec ruby #{bm}"
46
+ end
47
+ end
48
+
49
+ desc "CI run"
50
+ task ci: %i[test benchmark]
51
+
52
+ namespace :build do
53
+ desc "Build the MRI gem"
54
+ task :mri do
55
+ sh "gem build wayfarer.gemspec --verbose"
56
+ sh "mkdir -p build"
57
+ sh "mv wayfarer-*.gem build"
58
+ end
59
+
60
+ desc "Build the MRI gem"
61
+ task :jruby do
62
+ sh "gem build wayfarer-jruby.gemspec --verbose"
63
+ sh "mkdir -p build"
64
+ sh "mv wayfarer-jruby-*.gem build"
65
+ end
66
+ end
67
+
68
+ desc "Remove build directory"
69
+ task :clean do
70
+ sh "rm -rf build"
71
+ end
72
+
73
+ desc "Start a preloaded REPL"
74
+ task :repl do
75
+ require_relative "lib/wayfarer"
76
+
77
+ include Wayfarer
78
+ include Wayfarer::HTTPAdapters
79
+ include Wayfarer::Routing
80
+ include Wayfarer::Frontiers
81
+
82
+ begin
83
+ require "pry"
84
+ Pry.new.repl(self)
85
+ rescue LoadError
86
+ require "irb"
87
+ ARGV.clear
88
+ IRB.start
89
+ end
90
+ end
91
+
92
+ desc %(List lines that contain "FIXME" or "TODO")
93
+ task :todo do
94
+ sh %(grep -rn "\\(FIXME\\|TODO\\)" lib spec | tr -s [:space:])
95
+ end
96
+
97
+ task :test_app do
98
+ mutex = Mutex.new
99
+ cvar = ConditionVariable.new
100
+
101
+ Thread.new do
102
+ Rack::Handler::WEBrick.run(
103
+ TestApp,
104
+ Port: 9876,
105
+ BindAddress: "localhost",
106
+ Logger: WEBrick::Log.new("/dev/null"),
107
+ AccessLog: [],
108
+ StartCallback: proc { cvar.signal }
109
+ )
110
+ end
111
+
112
+ mutex.lock
113
+ cvar.wait(mutex)
114
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../lib/wayfarer"
4
+
5
+ require "benchmark"
6
+ require "parallel" unless RUBY_PLATFORM == "java"
7
+ require "faker"
8
+
9
+ include Wayfarer::Frontiers
10
+
11
+ def print_separator
12
+ puts "-" * `tput cols`.to_i
13
+ end
14
+
15
+ # URI count is kept low on purpose because this file is run on Travis CI.
16
+ # Bump up the numbers when running locally.
17
+ URI_COUNT = 10_000
18
+ SAMPLE_COUNT = URI_COUNT * 0.01
19
+ CYCLE_COUNT = 20
20
+
21
+ FRONTIERS = RUBY_PLATFORM == "java" ? {
22
+ MemoryFrontier => "memory",
23
+ RedisFrontier => "redis"
24
+ } : {
25
+ MemoryBloomfilter => "memory_bloom",
26
+ MemoryFrontier => "memory",
27
+ MemoryTrieFrontier => "memory_trie",
28
+ RedisBloomfilter => "redis_bloom",
29
+ RedisFrontier => "redis"
30
+ }
31
+
32
+ label_width = FRONTIERS.reduce(0) { |acc, (_, label)|
33
+ acc > (l = label.length) ? acc : l
34
+ }
35
+
36
+ puts "Generating #{URI_COUNT} URIs..."
37
+
38
+ uris = if RUBY_PLATFORM == "java"
39
+ Array.new(URI_COUNT) { Faker::Internet.url }
40
+ else
41
+ Parallel.map(URI_COUNT.times) { Faker::Internet.url }
42
+ end
43
+ samples = uris.sample(SAMPLE_COUNT)
44
+
45
+ puts "Done generating URIs"
46
+
47
+ print_separator
48
+ puts "Cache insertion"
49
+
50
+ Benchmark.bm do |bm|
51
+ FRONTIERS.each do |(klass, label)|
52
+ frontier = klass.new(Wayfarer::Configuration.new)
53
+ frontier.cache(*uris)
54
+
55
+ bm.report(label.ljust(label_width)) do
56
+ frontier.cache(*samples)
57
+ end
58
+
59
+ frontier.free
60
+ end
61
+ end
62
+
63
+ print_separator
64
+ puts "Cache detection"
65
+
66
+ Benchmark.bm do |bm|
67
+ FRONTIERS.each do |(klass, label)|
68
+ frontier = klass.new(Wayfarer::Configuration.new)
69
+ frontier.cache(*uris)
70
+
71
+ bm.report(label.ljust(label_width)) do
72
+ samples.each { |sample| frontier.cached?(sample) }
73
+ end
74
+
75
+ frontier.free
76
+ end
77
+ end
78
+
79
+ print_separator
80
+ puts "Cycling"
81
+
82
+ slices = samples.each_slice(CYCLE_COUNT)
83
+
84
+ Benchmark.bm do |bm|
85
+ FRONTIERS.each do |(klass, label)|
86
+ frontier = klass.new(Wayfarer::Configuration.new)
87
+
88
+ bm.report(label.ljust(label_width)) do
89
+ slices.each do |samples|
90
+ frontier.stage(*samples)
91
+ frontier.cycle
92
+ end
93
+ end
94
+
95
+ frontier.free
96
+ end
97
+ end
98
+
99
+ print_separator
100
+ puts "Cache detection false positives/negatives"
101
+
102
+ trials = samples.count / 2
103
+
104
+ positives = samples.sample(trials)
105
+ negatives = if RUBY_PLATFORM == "java"
106
+ Array.new(trials) { Faker::Internet.url }
107
+ else
108
+ Parallel.map(trials.times) { Faker::Internet.url }
109
+ end
110
+
111
+ FRONTIERS.each do |(klass, label)|
112
+ frontier = klass.new(Wayfarer::Configuration.new)
113
+
114
+ false_positives = false_negatives = 0
115
+
116
+ positives.each do |positive| frontier.cache(positive) end
117
+
118
+ positives.each do |positive|
119
+ false_positives += 1 unless frontier.cached?(positive)
120
+ end
121
+
122
+ negatives.each do |negative|
123
+ false_positives += 1 if frontier.cached?(negative)
124
+ end
125
+
126
+ fp_percentage = if false_positives.zero?
127
+ 0
128
+ else
129
+ (trials.to_f / false_positives).round(3)
130
+ end
131
+
132
+ fn_percentage = if false_negatives.zero?
133
+ 0
134
+ else
135
+ (trials.to_f / false_negatives).round(3)
136
+ end
137
+
138
+ puts "* #{label.ljust(label_width)}"
139
+ puts " * False positives: #{false_positives} (#{fp_percentage}%)"
140
+ puts " * False negatives: #{false_negatives} (#{fn_percentage}%)"
141
+
142
+ frontier.free
143
+ end
data/bin/wayfarer ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "logger"
5
+ require "pathname"
6
+ require "time"
7
+ require "active_support/inflector"
8
+ require "thor"
9
+
10
+ require_relative "../lib/wayfarer"
11
+
12
+ module Wayfarer
13
+ class CLI < Thor
14
+ class_option :log_level, type: :string, default: "info"
15
+
16
+ desc "exec FILE URI",
17
+ "Run the job defined in FILE starting from URI(s)"
18
+ def exec(file, uri)
19
+ set_log_level(options)
20
+ load_class_from_file(file).perform(uri)
21
+ end
22
+
23
+ option :queue_adapter, type: :string, default: "inline"
24
+ option :wait, type: :string
25
+ desc "enqueue FILE URI",
26
+ "Run the job defined in FILE starting from URI(s)"
27
+ def enqueue(file, uri)
28
+ set_log_level(options)
29
+ set_queue_adapter(options)
30
+
31
+ if wait = options[:wait]
32
+ delayed_seconds = differing_seconds_from_string(wait)
33
+ load_class_from_file(file).set(wait: delayed_seconds).perform_later(uri)
34
+ else
35
+ load_class_from_file(file).perform_later(uri)
36
+ end
37
+ end
38
+
39
+ desc "route FILE URI",
40
+ "Output the first matching route from FILE for URI"
41
+ def route(file, uri)
42
+ set_log_level(options)
43
+
44
+ job = load_class_from_file(file)
45
+
46
+ action, params = job.router.route(URI(uri))
47
+
48
+ if action
49
+ puts "Dispatching to :#{action} with parameters: #{params}"
50
+ else
51
+ puts "No matching route"
52
+ end
53
+ end
54
+
55
+ desc "version", "Print the version"
56
+ def version
57
+ puts Wayfarer::VERSION
58
+ end
59
+
60
+ private
61
+
62
+ def set_log_level(options)
63
+ if level = options[:log_level]
64
+ Wayfarer.logger.level = log_level_from_string(level)
65
+ end
66
+ end
67
+
68
+ def set_queue_adapter(options)
69
+ if adapter = options[:queue_adapter]
70
+ ActiveJob::Base.queue_adapter = adapter
71
+ end
72
+ end
73
+
74
+ def log_level_from_string(str)
75
+ case str.downcase
76
+ when "unknown" then Logger::UNKNOWN
77
+ when "debug" then Logger::DEBUG
78
+ when "error" then Logger::ERROR
79
+ when "fatal" then Logger::FATAL
80
+ when "info" then Logger::INFO
81
+ when "warn" then Logger::WARN
82
+ end
83
+ end
84
+
85
+ def differing_seconds_from_string(str)
86
+ # RuboCop turned this into an art piece
87
+ if secs = begin
88
+ Integer(secs)
89
+ rescue
90
+ nil
91
+ end
92
+ secs
93
+ elsif time = begin
94
+ Time.parse(str)
95
+ rescue
96
+ nil
97
+ end
98
+ time - Time.now
99
+ else
100
+ # TODO: Get rid of this
101
+ require "chronic"
102
+ Chronic.parse(str) - Time.now
103
+ end
104
+ end
105
+
106
+ def load_class_from_file(file)
107
+ path = File.join(Dir.pwd, file.chomp(".rb"))
108
+ base_name = Pathname.new(path).basename.to_s
109
+
110
+ require path
111
+ base_name.camelize.constantize
112
+ end
113
+ end
114
+ end
115
+
116
+ Wayfarer::CLI.start(ARGV)
data/docs/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ _site
2
+ .sass-cache
data/docs/_config.yml ADDED
@@ -0,0 +1,15 @@
1
+ gems:
2
+ - bourbon
3
+ - neat
4
+
5
+ markdown: kramdown
6
+ sass:
7
+ style: :compressed
8
+
9
+ kramdown:
10
+ input: GFM
11
+ syntax_highlighter: rouge
12
+
13
+ highlighter: rouge
14
+
15
+ title: Wayfarer
@@ -0,0 +1,7 @@
1
+ <!-- See: https://ricostacruz.com/til/relative-paths-in-jekyll -->
2
+ {% assign base = '' %}
3
+ {% assign depth = page.url | split: '/' | size | minus: 1 %}
4
+ {% if depth <= 1 %}{% assign base = '.' %}
5
+ {% elsif depth == 2 %}{% assign base = '..' %}
6
+ {% elsif depth == 3 %}{% assign base = '../..' %}
7
+ {% elsif depth == 4 %}{% assign base = '../../..' %}{% endif %}
@@ -0,0 +1,10 @@
1
+ <head>
2
+ <title>{{page.title}} | Wayfarer</title>
3
+ <meta charset="utf-8">
4
+ <meta name="viewport" content="width=device-width">
5
+ <link rel="stylesheet" href="{{base}}/css/screen.css">
6
+ <link
7
+ rel="stylesheet"
8
+ href="//brick.a.ssl.fastly.net/Titillium:400,600/Roboto+Mono:400,700">
9
+ <script src="{{base}}/js/navigation.js"></script>
10
+ </head>