wayfarer 0.0.3

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.
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
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::ProtocolRule do
5
+ describe "#matches?" do
6
+ context "with a string" do
7
+ subject(:rule) { ProtocolRule.new(:http) }
8
+
9
+ context "with matching URI" do
10
+ let(:uri) { URI("http://example.com") }
11
+
12
+ it "returns true" do
13
+ expect(rule.matches?(uri)).to be true
14
+ end
15
+ end
16
+
17
+ context "with mismatching URI" do
18
+ let(:uri) { URI("https://example.com") }
19
+
20
+ it "returns true" do
21
+ expect(rule.matches?(uri)).to be false
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::QueryRule do
5
+ subject(:rule) { QueryRule.new(constraints) }
6
+
7
+ describe "String constraints" do
8
+ let(:constraints) { Hash[arg: "foo"] }
9
+
10
+ context "with matching query field value" do
11
+ let(:uri) { URI("http://example.com?arg=foo") }
12
+
13
+ it "returns true" do
14
+ expect(rule.matches?(uri)).to be true
15
+ end
16
+ end
17
+
18
+ context "with mismatching query field value" do
19
+ let(:uri) { URI("http://example.com?arg=bar") }
20
+
21
+ it "returns false" do
22
+ expect(rule.matches?(uri)).to be false
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "Integer constraints" do
28
+ let(:constraints) { Hash[arg: 0] }
29
+
30
+ context "with matching query field value" do
31
+ let(:uri) { URI("http://example.com?arg=0") }
32
+
33
+ it "returns true" do
34
+ expect(rule.matches?(uri)).to be true
35
+ end
36
+ end
37
+
38
+ context "with mismatching query field value" do
39
+ let(:uri) { URI("http://example.com?arg=1") }
40
+
41
+ it "returns false" do
42
+ expect(rule.matches?(uri)).to be false
43
+ end
44
+ end
45
+
46
+ context "with non-numeric query field value" do
47
+ let(:uri) { URI("http://example.com?arg=foo") }
48
+
49
+ it "returns false" do
50
+ expect(rule.matches?(uri)).to be false
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "Regexp constraints" do
56
+ let(:constraints) { Hash[arg: /foo/] }
57
+
58
+ context "with matching query field value" do
59
+ let(:uri) { URI("http://example.com?arg=foo") }
60
+
61
+ it "returns true" do
62
+ expect(rule.matches?(uri)).to be true
63
+ end
64
+ end
65
+
66
+ context "with mismatching query field value" do
67
+ let(:uri) { URI("http://example.com?arg=bar") }
68
+
69
+ it "returns false" do
70
+ expect(rule.matches?(uri)).to be false
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "Range constraints" do
76
+ let(:constraints) { Hash[arg: 1..10] }
77
+
78
+ context "with matching query field value" do
79
+ let(:uri) { URI("http://example.com?arg=5") }
80
+
81
+ it "returns true" do
82
+ expect(rule.matches?(uri)).to be true
83
+ end
84
+ end
85
+
86
+ context "with mismatching query field value" do
87
+ let(:uri) { URI("http://example.com?arg=11") }
88
+
89
+ it "returns false" do
90
+ expect(rule.matches?(uri)).to be false
91
+ end
92
+ end
93
+
94
+ context "with non-numeric query field value" do
95
+ let(:uri) { URI("http://example.com?arg=foo") }
96
+
97
+ it "returns false" do
98
+ expect(rule.matches?(uri)).to be false
99
+ end
100
+ end
101
+ end
102
+
103
+ describe "Compound constraints" do
104
+ let(:constraints) do
105
+ Hash[foo: 1..5, bar: /baz/, qux: "zot", toto: 2]
106
+ end
107
+
108
+ context "with matching query field values" do
109
+ let(:uri) { URI("http://example.com?foo=4&bar=bazqux&qux=zot&toto=2") }
110
+
111
+ it "returns true" do
112
+ expect(rule.matches?(uri)).to be true
113
+ end
114
+ end
115
+
116
+ context "with mismatching query field values" do
117
+ let(:uri) { URI("http://example.com?foo=bar&bar=qux&qux=6toto=0") }
118
+
119
+ it "returns false" do
120
+ expect(rule.matches?(uri)).to be false
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::Router do
5
+ subject(:router) { Router.new }
6
+
7
+ describe "#forbid" do
8
+ it "forbids URIs" do
9
+ router.forbid(host: "example.com")
10
+ expect(router.forbids?(URI("http://example.com"))).to be true
11
+
12
+ router.forbid { host "google.com" }
13
+
14
+ expect(router.forbids?(URI("http://google.com"))).to be true
15
+ expect(router.allows?(URI("http://google.com"))).to be false
16
+ end
17
+ end
18
+
19
+ describe "#route" do
20
+ context "with matching route" do
21
+ it "returns the registered payload and parameters" do
22
+ router.host "example.com", path: "/{barqux}", to: :foo
23
+
24
+ uri = URI("http://example.com/42")
25
+ method, params = router.route(uri)
26
+
27
+ expect(method).to be :foo
28
+ expect(params).to eq("barqux" => "42")
29
+ end
30
+ end
31
+
32
+ context "with mismatching route" do
33
+ it "returns false" do
34
+ router.host "example.com", path: "/{barqux}", to: :foo
35
+
36
+ uri = URI("http://google.com")
37
+
38
+ expect(router.route(uri)).to be false
39
+ end
40
+ end
41
+
42
+ context "with forbidden URI" do
43
+ it "returns false" do
44
+ router.host "example.com", path: "/{barqux}", to: :foo
45
+ router.forbid.host "example.com"
46
+
47
+ uri = URI("http://example.com")
48
+
49
+ expect(router.route(uri)).to be false
50
+ end
51
+ end
52
+
53
+ context "with nested conflicting target actions" do
54
+ it "returns the expected parameters" do
55
+ router.host "example.com", to: :foo do
56
+ path "/{barqux}", to: :bar
57
+ end
58
+
59
+ uri = URI("http://example.com/42")
60
+ method, params = router.route(uri)
61
+
62
+ expect(method).to be :bar
63
+ expect(params).to eq("barqux" => "42")
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::Rule do
5
+ subject(:rule) { Rule.new }
6
+
7
+ describe "#initialize" do
8
+ it "evaluates the Proc in its instance context" do
9
+ this = nil
10
+ rule = Rule.new { this = self }
11
+ expect(this).to be rule
12
+ end
13
+
14
+ it "builds the expected Rule chain from options" do
15
+ rule = Rule.new(host: "example.com", query: { bar: 42 })
16
+
17
+ first = rule.child_rules.first
18
+ second = first.child_rules.first
19
+ third = second.child_rules.first
20
+
21
+ expect(first).to be_a HostRule
22
+ expect(second).to be_a QueryRule
23
+ end
24
+ end
25
+
26
+ describe "#params" do
27
+ it "returns an empty Hash" do
28
+ expect(rule.params(URI("http://example.com"))).to eq({})
29
+ end
30
+ end
31
+
32
+ describe "#matching_rule_chain" do
33
+ let(:uri) { URI("http://example.com/foo/bar") }
34
+
35
+ context "with matching Rule" do
36
+ let(:host_rule_a) { HostRule.new("example.com") }
37
+ let(:host_rule_b) { HostRule.new("google.com") }
38
+ let(:path_rule_a) { PathRule.new("/{alpha}/{beta}") }
39
+ let(:path_rule_b) { PathRule.new("/{gamma}/{delta}") }
40
+
41
+ before do
42
+ host_rule_a.send(:append_child_rule, path_rule_a)
43
+ host_rule_a.send(:append_child_rule, path_rule_b)
44
+
45
+ host_rule_b.send(:append_child_rule, path_rule_a)
46
+ host_rule_b.send(:append_child_rule, path_rule_b)
47
+ end
48
+
49
+ subject(:rule) do
50
+ rule = Rule.new
51
+ rule.send(:append_child_rule, host_rule_a)
52
+ rule.send(:append_child_rule, host_rule_b)
53
+ rule
54
+ end
55
+
56
+ it "returns the expected Array" do
57
+ expect(rule.matching_rule_chain(uri)).to eq [
58
+ rule, host_rule_a, path_rule_a
59
+ ]
60
+ end
61
+ end
62
+
63
+ context "without matching Rule" do
64
+ subject(:rule) do
65
+ rule = Rule.new
66
+ rule.host("yahoo.com")
67
+ rule.host("google.com")
68
+ rule
69
+ end
70
+
71
+ it "returns an empty Array" do
72
+ expect(rule.matching_rule_chain(uri)).to eq []
73
+ end
74
+ end
75
+ end
76
+
77
+ describe "#params_from_rule_chain" do
78
+ let(:uri) { URI("http://example.com/foo/bar") }
79
+
80
+ context "with matching Rule" do
81
+ subject(:rule_chain) do
82
+ rule = Rule.new
83
+ rule.host("example.com").path("/{alpha}/{beta}")
84
+ rule.host("example.com").path("/{foo}/{bar}")
85
+ rule.matching_rule_chain(uri)
86
+ end
87
+
88
+ it "returns the expected URI parameters" do
89
+ expect(rule.send(:params_from_rule_chain, rule_chain, uri)).to eq("alpha" => "foo", "beta" => "bar")
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "#invoke" do
95
+ let(:uri) { URI("http://example.com/foo/bar") }
96
+
97
+ context "with matching Rule" do
98
+ subject(:rule) do
99
+ rule = Rule.new
100
+ rule.host("example.com").path("/{alpha}/{beta}")
101
+ rule
102
+ end
103
+
104
+ it "returns a truthy value" do
105
+ expect(rule.invoke(uri)).to be_truthy
106
+ end
107
+
108
+ it "returns the URI parameters" do
109
+ _, params = rule.invoke(uri)
110
+ expect(params).to eq("alpha" => "foo", "beta" => "bar")
111
+ end
112
+ end
113
+
114
+ context "with mismatching Rule" do
115
+ subject(:rule) do
116
+ rule = Rule.new
117
+ rule.host("google.com").path("/{alpha}/{beta}")
118
+ rule
119
+ end
120
+
121
+ it "returns false" do
122
+ expect(rule.invoke(uri)).to be false
123
+ end
124
+ end
125
+ end
126
+
127
+ describe "#uri" do
128
+ it "adds a URIRule as a sub-rule" do
129
+ rule.uri("http://example.com/foo/bar")
130
+ expect(rule.child_rules.first).to be_a URIRule
131
+ end
132
+
133
+ it "returns the added URIRule" do
134
+ expect(rule.uri("http://example.com/foo/bar")).to be_a URIRule
135
+ end
136
+ end
137
+
138
+ describe "#host" do
139
+ it "adds a HostRule as a sub-rule" do
140
+ rule.host("example.com")
141
+ expect(rule.child_rules.first).to be_a HostRule
142
+ end
143
+
144
+ it "returns the added HostRule" do
145
+ expect(rule.host("example.com")).to be_a HostRule
146
+ end
147
+ end
148
+
149
+ describe "#path" do
150
+ it "adds a PathRule as a sub-rule" do
151
+ rule.path("/foo/bar")
152
+ expect(rule.child_rules.first).to be_a PathRule
153
+ end
154
+
155
+ it "returns the added PathRule" do
156
+ expect(rule.path("/foo/bar")).to be_a PathRule
157
+ end
158
+ end
159
+
160
+ describe "#query" do
161
+ it "adds a QueryRule as a sub-rule" do
162
+ rule.query(foo: "bar")
163
+ expect(rule.child_rules.first).to be_a QueryRule
164
+ end
165
+
166
+ it "returns the added QueryRule" do
167
+ expect(rule.query(foo: "bar")).to be_a QueryRule
168
+ end
169
+ end
170
+
171
+ describe "#protocol" do
172
+ it "adds a ProtocolRule as a sub-rule" do
173
+ rule.protocol(:https)
174
+ expect(rule.child_rules.first).to be_a ProtocolRule
175
+ end
176
+
177
+ it "returns the added QueryRule" do
178
+ expect(rule.protocol(:https)).to be_a ProtocolRule
179
+ end
180
+ end
181
+
182
+ describe "#if" do
183
+ it "adds a CustomRule as a sub-rule" do
184
+ rule.if -> () { true }
185
+ expect(rule.child_rules.first).to be_a CustomRule
186
+ end
187
+
188
+ it "returns the added QueryRule" do
189
+ expect(rule.if -> () { true }).to be_a CustomRule
190
+ end
191
+ end
192
+
193
+ describe "#filetypes" do
194
+ it "adds a FiletypesRule as a sub-rule" do
195
+ rule.filetypes [:png, :jpg]
196
+ expect(rule.child_rules.first).to be_a FiletypesRule
197
+ end
198
+
199
+ it "returns the added FiletypeRule" do
200
+ expect(rule.filetypes [:png]).to be_a FiletypesRule
201
+ end
202
+ end
203
+
204
+ describe "#build_child_rule_chain_from_options" do
205
+ subject(:rule) do
206
+ rule = Rule.new
207
+ rule.build_child_rule_chain_from_options(opts)
208
+ rule
209
+ end
210
+
211
+ describe ":path option" do
212
+ let(:opts) { { path: "/foo" } }
213
+
214
+ it "adds a PathRule" do
215
+ expect(rule.child_rules.first).to be_a PathRule
216
+ end
217
+ end
218
+
219
+ describe ":query option" do
220
+ let(:opts) { { query: { bar: "qux" } } }
221
+
222
+ it "adds a QueryRule" do
223
+ expect(rule.child_rules.first).to be_a QueryRule
224
+ end
225
+ end
226
+
227
+ describe ":host option" do
228
+ let(:opts) { { host: "example.com" } }
229
+
230
+ it "adds a HostRule" do
231
+ expect(rule.child_rules.first).to be_a HostRule
232
+ end
233
+ end
234
+
235
+ context "with multiple options present" do
236
+ let(:opts) do
237
+ { host: "example.com", path: "/foo", query: { bar: "qux" } }
238
+ end
239
+
240
+ it "adds chained sub-rules" do
241
+ first = rule.child_rules.first
242
+ second = first.child_rules.first
243
+ third = second.child_rules.first
244
+
245
+ expect(first).to be_a HostRule
246
+ expect(second).to be_a PathRule
247
+ expect(third).to be_a QueryRule
248
+ end
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::URIRule do
5
+ subject(:rule) { URIRule.new("http://example.com/foo/bar") }
6
+
7
+ describe "#matches?" do
8
+ context "with matching URI" do
9
+ let(:uri) { URI("http://example.com/foo/bar") }
10
+
11
+ it "returns true" do
12
+ expect(rule.matches?(uri)).to be true
13
+ end
14
+ end
15
+
16
+ context "with mismatching URI" do
17
+ let(:uri) { URI("http://example.com/foo/qux") }
18
+
19
+ it "returns true" do
20
+ expect(rule.matches?(uri)).to be false
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+ require "securerandom"
3
+
4
+ RSpec.shared_examples "Frontier" do |klass|
5
+ subject(:frontier) { klass.new(Configuration.new) }
6
+
7
+ after { frontier.free }
8
+
9
+ describe "#stage" do
10
+ let(:uri) { "http://example.com/foo#bar" }
11
+
12
+ it "stages a URI" do
13
+ frontier.stage("http://example.com")
14
+ expect(frontier.staged?("http://example.com")).to be true
15
+ end
16
+
17
+ it "stages multiple URIs" do
18
+ frontier.stage("http://example.com", "http://google.com")
19
+ expect(frontier.staged?("http://example.com")).to be true
20
+ expect(frontier.staged?("http://google.com")).to be true
21
+ end
22
+ end
23
+
24
+ describe "#cache" do
25
+ it "caches a URI" do
26
+ frontier.cache("http://example.com")
27
+ expect(frontier.cached?("http://example.com")).to be true
28
+ end
29
+
30
+ it "caches multiple URIs" do
31
+ frontier.cache("http://example.com", "http://google.com")
32
+ expect(frontier.cached?("http://example.com")).to be true
33
+ expect(frontier.cached?("http://google.com")).to be true
34
+ end
35
+ end
36
+
37
+ describe "#cycle" do
38
+ let(:uri) { "http://example.com" }
39
+
40
+ it "does not stage the same URI twice" do
41
+ 2.times { frontier.stage(uri) }
42
+
43
+ expect { frontier.cycle }.to change { frontier.current_uris.count }.by(1)
44
+ end
45
+
46
+ it "caches URIs" do
47
+ frontier.stage(uri)
48
+
49
+ 2.times { frontier.cycle }
50
+
51
+ expect(frontier.cached?(uri)).to be true
52
+ end
53
+
54
+ context "with staged URIs" do
55
+ before { frontier.stage(uri) }
56
+
57
+ it "swaps current and staged URIs" do
58
+ frontier.cycle
59
+ expect(frontier.current_uris).to eq [URI(uri)]
60
+ expect(frontier.staged_uris).to eq []
61
+ end
62
+
63
+ it "returns true" do
64
+ expect(frontier.cycle).to be true
65
+ end
66
+ end
67
+
68
+ context "without staged URIs" do
69
+ it "returns false" do
70
+ expect(frontier.cycle).to be false
71
+ end
72
+ end
73
+
74
+ it "does not set cached URIs as current" do
75
+ frontier.cache(uri)
76
+ frontier.stage(uri)
77
+ frontier.cycle
78
+
79
+ expect(frontier.current_uris).to be_empty
80
+ end
81
+
82
+ context "when circulation is allowed" do
83
+ subject(:frontier) do
84
+ klass.new(Configuration.new(allow_circulation: true))
85
+ end
86
+
87
+ it "sets cached URIs as current" do
88
+ 3.times do
89
+ frontier.stage(uri)
90
+ frontier.cycle
91
+ expect(frontier.current_uris).to eq [URI(uri)]
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ require_relative "../lib/wayfarer"
3
+
4
+ require("bundler") && Bundler.require
5
+
6
+ include Wayfarer
7
+ include Wayfarer::HTTPAdapters
8
+ include Wayfarer::Routing
9
+ include Wayfarer::Frontiers
10
+
11
+ if RUBY_PLATFORM == "java"
12
+ Wayfarer::Frontiers::MemoryBloomfilter = \
13
+ Wayfarer::Frontiers::MemoryTrieFrontier = \
14
+ Wayfarer::Frontiers::RedisBloomfilter = nil
15
+ end
16
+
17
+ Dir["./spec/shared/**/*.rb"].sort.each { |file| require file }
18
+
19
+ module SpecHelpers
20
+ def jruby?
21
+ RUBY_PLATFORM == "java"
22
+ end
23
+
24
+ def test_app(path)
25
+ URI("http://localhost:9876#{path}")
26
+ end
27
+
28
+ def fetch_page(uri)
29
+ NetHTTPAdapter.instance.fetch(URI(uri))
30
+ end
31
+
32
+ def html_fragment(html)
33
+ Nokogiri::HTML.fragment(html)
34
+ end
35
+
36
+ def node_set(html)
37
+ html_fragment(html).css("*")
38
+ end
39
+ end
40
+
41
+ RSpec.configure do |config|
42
+ config.include(SpecHelpers)
43
+
44
+ config.before do
45
+ Wayfarer.config.reset!
46
+ Wayfarer.config.selenium_argv = [:phantomjs]
47
+ end
48
+
49
+ config.before(integration: true) do
50
+ Wayfarer.logger.level = :fatal
51
+ end
52
+
53
+ config.after(integration: true) do
54
+ Wayfarer.logger.level = :debug
55
+ end
56
+
57
+ config.before(mri_only: true) do
58
+ skip("Not supported on JRuby") and fail if RUBY_PLATFORM == "java"
59
+ end
60
+
61
+ config.alias_example_to :they
62
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer do
5
+ describe "::VERSION" do
6
+ it("is present") { expect(defined? Wayfarer::VERSION).not_to be nil }
7
+ end
8
+
9
+ describe "::logger, ::logger=" do
10
+ it "returns and alters the logger" do
11
+ expect(Wayfarer.logger).to be_a Logger
12
+ end
13
+ end
14
+
15
+ describe "::config" do
16
+ it "alters keys and values" do
17
+ Wayfarer.config.foo = :bar
18
+ expect(Wayfarer.config.foo).to be :bar
19
+
20
+ Wayfarer.config { |config| config.baz = :qux }
21
+ expect(Wayfarer.config.baz).to be :qux
22
+ end
23
+ end
24
+ end