dh_easy-core 0.2.2
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/.gitignore +12 -0
- data/.travis.yml +7 -0
- data/.yardopts +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +20 -0
- data/Rakefile +22 -0
- data/dh_easy-core.gemspec +50 -0
- data/doc/DhEasy.html +117 -0
- data/doc/DhEasy/Core.html +1590 -0
- data/doc/DhEasy/Core/Config.html +311 -0
- data/doc/DhEasy/Core/Exception.html +117 -0
- data/doc/DhEasy/Core/Exception/OutdatedError.html +135 -0
- data/doc/DhEasy/Core/Helper.html +117 -0
- data/doc/DhEasy/Core/Helper/Cookie.html +1070 -0
- data/doc/DhEasy/Core/Mock.html +282 -0
- data/doc/DhEasy/Core/Mock/FakeDb.html +3779 -0
- data/doc/DhEasy/Core/Mock/FakeExecutor.html +3289 -0
- data/doc/DhEasy/Core/Mock/FakeFinisher.html +160 -0
- data/doc/DhEasy/Core/Mock/FakeParser.html +160 -0
- data/doc/DhEasy/Core/Mock/FakeSeeder.html +160 -0
- data/doc/DhEasy/Core/Plugin.html +117 -0
- data/doc/DhEasy/Core/Plugin/CollectionVault.html +299 -0
- data/doc/DhEasy/Core/Plugin/ConfigBehavior.html +541 -0
- data/doc/DhEasy/Core/Plugin/ContextIntegrator.html +445 -0
- data/doc/DhEasy/Core/Plugin/Executor.html +259 -0
- data/doc/DhEasy/Core/Plugin/ExecutorBehavior.html +344 -0
- data/doc/DhEasy/Core/Plugin/Finisher.html +265 -0
- data/doc/DhEasy/Core/Plugin/FinisherBehavior.html +142 -0
- data/doc/DhEasy/Core/Plugin/InitializeHook.html +220 -0
- data/doc/DhEasy/Core/Plugin/Parser.html +270 -0
- data/doc/DhEasy/Core/Plugin/ParserBehavior.html +235 -0
- data/doc/DhEasy/Core/Plugin/Seeder.html +674 -0
- data/doc/DhEasy/Core/Plugin/SeederBehavior.html +142 -0
- data/doc/DhEasy/Core/SmartCollection.html +1087 -0
- data/doc/_index.html +364 -0
- data/doc/class_list.html +51 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +496 -0
- data/doc/file.README.html +91 -0
- data/doc/file_list.html +56 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +91 -0
- data/doc/js/app.js +303 -0
- data/doc/js/full_list.js +216 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +939 -0
- data/doc/top-level-namespace.html +110 -0
- data/lib/dh_easy/core.rb +257 -0
- data/lib/dh_easy/core/config.rb +27 -0
- data/lib/dh_easy/core/exception.rb +8 -0
- data/lib/dh_easy/core/exception/outdated_error.rb +9 -0
- data/lib/dh_easy/core/helper.rb +8 -0
- data/lib/dh_easy/core/helper/cookie.rb +209 -0
- data/lib/dh_easy/core/mock.rb +45 -0
- data/lib/dh_easy/core/mock/fake_db.rb +561 -0
- data/lib/dh_easy/core/mock/fake_executor.rb +373 -0
- data/lib/dh_easy/core/mock/fake_finisher.rb +28 -0
- data/lib/dh_easy/core/mock/fake_parser.rb +33 -0
- data/lib/dh_easy/core/mock/fake_seeder.rb +28 -0
- data/lib/dh_easy/core/plugin.rb +19 -0
- data/lib/dh_easy/core/plugin/collection_vault.rb +23 -0
- data/lib/dh_easy/core/plugin/config_behavior.rb +43 -0
- data/lib/dh_easy/core/plugin/context_integrator.rb +60 -0
- data/lib/dh_easy/core/plugin/executor.rb +19 -0
- data/lib/dh_easy/core/plugin/executor_behavior.rb +32 -0
- data/lib/dh_easy/core/plugin/finisher.rb +19 -0
- data/lib/dh_easy/core/plugin/finisher_behavior.rb +9 -0
- data/lib/dh_easy/core/plugin/initialize_hook.rb +17 -0
- data/lib/dh_easy/core/plugin/parser.rb +19 -0
- data/lib/dh_easy/core/plugin/parser_behavior.rb +17 -0
- data/lib/dh_easy/core/plugin/seeder.rb +44 -0
- data/lib/dh_easy/core/plugin/seeder_behavior.rb +9 -0
- data/lib/dh_easy/core/smart_collection.rb +236 -0
- data/lib/dh_easy/core/version.rb +6 -0
- metadata +249 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.20
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
pathId = "";
|
19
|
+
relpath = '';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="class_list.html?1"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="_index.html">Index</a> »
|
40
|
+
|
41
|
+
|
42
|
+
<span class="title">Top Level Namespace</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div id="content"><h1>Top Level Namespace
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
</h1>
|
67
|
+
<div class="box_info">
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
</div>
|
80
|
+
|
81
|
+
<h2>Defined Under Namespace</h2>
|
82
|
+
<p class="children">
|
83
|
+
|
84
|
+
|
85
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="DhEasy.html" title="DhEasy (module)">DhEasy</a></span>
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
</p>
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
</div>
|
101
|
+
|
102
|
+
<div id="footer">
|
103
|
+
Generated on Wed Dec 4 23:00:02 2019 by
|
104
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
105
|
+
0.9.20 (ruby-2.5.3).
|
106
|
+
</div>
|
107
|
+
|
108
|
+
</div>
|
109
|
+
</body>
|
110
|
+
</html>
|
data/lib/dh_easy/core.rb
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'faker'
|
3
|
+
require 'datahen'
|
4
|
+
require 'dh_easy/core/smart_collection'
|
5
|
+
require 'dh_easy/core/exception'
|
6
|
+
require 'dh_easy/core/plugin'
|
7
|
+
require 'dh_easy/core/helper'
|
8
|
+
require 'dh_easy/core/config'
|
9
|
+
require 'dh_easy/core/mock'
|
10
|
+
require 'dh_easy/core/version'
|
11
|
+
|
12
|
+
module DhEasy
|
13
|
+
module Core
|
14
|
+
class << self
|
15
|
+
# Get dh_easy-core gem root directory path.
|
16
|
+
# @private
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
def gem_root
|
20
|
+
File.expand_path File.join(File.dirname(__FILE__), '../..')
|
21
|
+
end
|
22
|
+
|
23
|
+
# Execute an action for all scripts within a directory.
|
24
|
+
#
|
25
|
+
# @param [String] dir Directory containing `.rb` scripts.
|
26
|
+
# @param [Hash] opts ({}) Configuration options.
|
27
|
+
# @option opts [Array] :except (nil) Literal file collection excluded from process.
|
28
|
+
#
|
29
|
+
# @yieldparam [String] path Script file path.
|
30
|
+
def all_scripts dir, opts = {}, &block
|
31
|
+
excluded_files = (opts[:except] || []).map{|f|File.expand_path File.join(dir, f)}
|
32
|
+
files = Dir[File.join(File.expand_path(dir), '*.rb')] - excluded_files
|
33
|
+
block ||= proc{}
|
34
|
+
files.sort.each &block
|
35
|
+
end
|
36
|
+
|
37
|
+
# Require all scripts within a directory.
|
38
|
+
#
|
39
|
+
# @param [String] dir Directory containing `.rb` scripts.
|
40
|
+
# @param [Hash] opts ({}) Configuration options.
|
41
|
+
# @option opts [Array] :except (nil) Literal file collection excluded from process.
|
42
|
+
def require_all dir, opts = {}
|
43
|
+
dir_list = real_dir_list = options = nil
|
44
|
+
real_except = (opts[:except] || []).map{|f| "#{f}.rb"}
|
45
|
+
options = opts.merge except: real_except
|
46
|
+
$LOAD_PATH.each do |load_path|
|
47
|
+
dir_list = Dir.glob File.join(load_path, dir)
|
48
|
+
dir_list.each do |real_dir|
|
49
|
+
next unless File.directory? real_dir
|
50
|
+
all_scripts(real_dir, options) {|file| require file}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Require all relative scripts paths within a directory.
|
56
|
+
#
|
57
|
+
# @param [String] dir Directory containing `.rb` scripts.
|
58
|
+
# @param [Hash] opts ({}) Configuration options.
|
59
|
+
# @option opts [Array] :except (nil) Literal file collection excluded from process.
|
60
|
+
def require_relative_all dir, opts = {}
|
61
|
+
real_except = (opts[:except] || []).map{|f| "#{f}.rb"}
|
62
|
+
options = opts.merge except: real_except
|
63
|
+
dir_list = Dir.glob dir
|
64
|
+
dir_list.each do |relative_dir|
|
65
|
+
real_dir = File.expand_path relative_dir
|
66
|
+
all_scripts(real_dir, options) {|file| require file}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Expose an environment into an object instance as methods.
|
71
|
+
#
|
72
|
+
# @param object Object instance to expose env into.
|
73
|
+
# @param [Array] env Hash with methods name as keys and blocks as actions.
|
74
|
+
#
|
75
|
+
# @return `object`
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
# class Foo
|
79
|
+
# def hello_person
|
80
|
+
# 'Hello person!'
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# env = {
|
85
|
+
# hello_world: lambda{return 'Hello world!'},
|
86
|
+
# hello_sky: proc{return 'Hello sky!'}
|
87
|
+
# }
|
88
|
+
# my_object = Foo.new
|
89
|
+
# DhEasy::Core.expose_to my_object, env
|
90
|
+
#
|
91
|
+
# puts my_object.hello_world
|
92
|
+
# # => 'Hello world!'
|
93
|
+
# puts my_object.hello_sky
|
94
|
+
# # => 'Hello sky!'
|
95
|
+
# puts my_object.hello_person
|
96
|
+
# # => 'Hello person!'
|
97
|
+
def expose_to object, env
|
98
|
+
metaclass = class << object; self; end
|
99
|
+
env.each do |key, block|
|
100
|
+
metaclass.send(:define_method, key, block)
|
101
|
+
end
|
102
|
+
object
|
103
|
+
end
|
104
|
+
|
105
|
+
# Retrieve instance methods from an object.
|
106
|
+
#
|
107
|
+
# @param object Object with instance methods.
|
108
|
+
# @param class_only (false) Will get class only methods when `true`.
|
109
|
+
#
|
110
|
+
# @return [Array]
|
111
|
+
#
|
112
|
+
# @example
|
113
|
+
# class Foo
|
114
|
+
# def hello_world
|
115
|
+
# 'Hello world!'
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# def hello_person
|
119
|
+
# 'Hello person!'
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# my_object = Foo.new
|
124
|
+
# DhEasy::Core.instance_methods_from my_object
|
125
|
+
# # => [:hello_world, :hello_person]
|
126
|
+
def instance_methods_from object, class_only = false
|
127
|
+
object.methods(!class_only) - Object.new.methods(!class_only)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Mock instances methods from the origin into target object.
|
131
|
+
#
|
132
|
+
# @param origin Object with instance methods to mock.
|
133
|
+
# @param target Object instance to mock methods into.
|
134
|
+
#
|
135
|
+
# @example
|
136
|
+
# class Boo
|
137
|
+
# attr_accessor :message
|
138
|
+
# def initialize
|
139
|
+
# message = 'Hello world!'
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# def hello_world
|
143
|
+
# message
|
144
|
+
# end
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
# class Foo
|
148
|
+
# def hello_person
|
149
|
+
# 'Hello person!'
|
150
|
+
# end
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# origin = Boo.new
|
154
|
+
# target = Foo.new
|
155
|
+
# DhEasy::Core.mock_instance_methods origin target
|
156
|
+
#
|
157
|
+
# puts target.hello_world
|
158
|
+
# # => 'Hello world!'
|
159
|
+
# puts target.hello_person
|
160
|
+
# # => 'Hello person!'
|
161
|
+
#
|
162
|
+
# origin.message = 'Hello world again!'
|
163
|
+
# puts target.hello_world
|
164
|
+
# # => 'Hello world again!'
|
165
|
+
def mock_instance_methods origin, target
|
166
|
+
# Get instance unique methods
|
167
|
+
method_list = instance_methods_from origin
|
168
|
+
method_list.delete :context_binding if method_list.include? :context_binding
|
169
|
+
|
170
|
+
# Build env reflecting origin unique methods
|
171
|
+
env = {}
|
172
|
+
method_list.each do |method|
|
173
|
+
env[method] = lambda{|*args|origin.send(method, *args)}
|
174
|
+
end
|
175
|
+
|
176
|
+
# Mock origin unique methods into target
|
177
|
+
expose_to target, env
|
178
|
+
end
|
179
|
+
|
180
|
+
# Generate a compatibility report from a origin and a fragment as a hash.
|
181
|
+
#
|
182
|
+
# @param [Array] origin Item collection to represent the universe.
|
183
|
+
# @param [Array] fragment Item collection to compare againt +origin+.
|
184
|
+
#
|
185
|
+
# @return [Hash]
|
186
|
+
# * `:missing [Array]` (`[]`) Methods on `fragment` only.
|
187
|
+
# * `:new [Array]` (`[]`) Methods on `origin` only.
|
188
|
+
# * `:is_compatible [Boolean]` true when all `fragment`'s methods are present on `origin`.
|
189
|
+
#
|
190
|
+
# @example Analyze when uncompatible `fragment` because of `origin` missing fields.
|
191
|
+
# DhEasy::Core.analyze_compatibility [1,2,3,4,5], [1,2,6]
|
192
|
+
# # => {missing: [6], new: [3,4,5], is_compatible: false}
|
193
|
+
#
|
194
|
+
# @example Analyze when compatible.
|
195
|
+
# DhEasy::Core.analyze_compatibility [1,2,3,4,5], [1,2,3]
|
196
|
+
# # => {missing: [], new: [4,5], is_compatible: true}
|
197
|
+
def analyze_compatibility origin, fragment
|
198
|
+
intersection = origin & fragment
|
199
|
+
{
|
200
|
+
missing: fragment - intersection,
|
201
|
+
new: origin - intersection,
|
202
|
+
is_compatible: (intersection.count == fragment.count)
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
# Deep stringify keys from a hash.
|
207
|
+
#
|
208
|
+
# @param [Hash] hash Source hash to stringify keys.
|
209
|
+
# @param [Boolean] should_clone (true) Target a hash clone to avoid affecting the same hash object.
|
210
|
+
#
|
211
|
+
# @return [Hash]
|
212
|
+
def deep_stringify_keys hash, should_clone = true
|
213
|
+
return hash unless hash.is_a? Hash
|
214
|
+
pair_collection = hash.map{|k,v| [k.to_s,v]}
|
215
|
+
target = should_clone ? {} : hash
|
216
|
+
target.clear
|
217
|
+
pair_collection.each do |pair|
|
218
|
+
key, value = pair
|
219
|
+
if value.is_a? Array
|
220
|
+
array = []
|
221
|
+
value.each do |item|
|
222
|
+
array << deep_stringify_keys(item, should_clone)
|
223
|
+
end
|
224
|
+
target[key] = array
|
225
|
+
next
|
226
|
+
end
|
227
|
+
target[key] = deep_stringify_keys(value, should_clone)
|
228
|
+
end
|
229
|
+
target
|
230
|
+
end
|
231
|
+
|
232
|
+
# Deep stringify all keys on hash object.
|
233
|
+
#
|
234
|
+
# @param [Hash] hash Hash to stringify keys.
|
235
|
+
#
|
236
|
+
# @return [Hash]
|
237
|
+
def deep_stringify_keys! hash
|
238
|
+
deep_stringify_keys hash, false
|
239
|
+
end
|
240
|
+
|
241
|
+
# Deep clone a hash while keeping it's values object references.
|
242
|
+
#
|
243
|
+
# @param [Hash] hash Hash to clone.
|
244
|
+
# @param [Boolean] should_clone (false) Clone values when true.
|
245
|
+
#
|
246
|
+
# @return [Hash] Hash clone.
|
247
|
+
def deep_clone hash, should_clone = false
|
248
|
+
target = {}
|
249
|
+
hash.each do |key, value|
|
250
|
+
value = value.is_a?(Hash) ? deep_clone(value, should_clone) : (should_clone ? value.clone : value)
|
251
|
+
target[key] = value
|
252
|
+
end
|
253
|
+
target
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module DhEasy
|
2
|
+
module Core
|
3
|
+
# Configuration manager tool useful for global configuration data accross
|
4
|
+
# the scraping process.
|
5
|
+
class Config
|
6
|
+
include DhEasy::Core::Plugin::InitializeHook
|
7
|
+
include DhEasy::Core::Plugin::ConfigBehavior
|
8
|
+
|
9
|
+
# {DhEasy::Core::Plugin::ConfigBehavior#config_collection_key}
|
10
|
+
alias :collection_key :config_collection_key
|
11
|
+
# {DhEasy::Core::Plugin::ConfigBehavior#config_collection}
|
12
|
+
alias :collection :config_collection
|
13
|
+
|
14
|
+
# Initialize config object
|
15
|
+
#
|
16
|
+
# @param [Hash] opts ({}) Configuration options.
|
17
|
+
#
|
18
|
+
# @see DhEasy::Core::Plugin::ConfigBehavior#initialize_hook_core_config_behavior
|
19
|
+
def initialize opts = {}
|
20
|
+
opts = opts.merge(
|
21
|
+
config_collection: opts[:collection]
|
22
|
+
)
|
23
|
+
initialize_hooks opts
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module DhEasy
|
2
|
+
module Core
|
3
|
+
module Helper
|
4
|
+
# Helper used for lower level cookie management.
|
5
|
+
class Cookie
|
6
|
+
class << self
|
7
|
+
# Parse request cookies on different formats.
|
8
|
+
#
|
9
|
+
# @param [String,Hash,Array] cookies Cookies to parse.
|
10
|
+
# @param [Hash] cookie_hash ({}) External hash to store parsed cookies.
|
11
|
+
#
|
12
|
+
# @return [Hash]
|
13
|
+
#
|
14
|
+
# @example Parse from string.
|
15
|
+
# parse_from_request 'aaa=111; bbb=222'
|
16
|
+
# # => {'aaa' => 111, 'bbb' => 222}
|
17
|
+
#
|
18
|
+
# @example Parse from array.
|
19
|
+
# cookies = [
|
20
|
+
# 'aaa=111',
|
21
|
+
# 'bbb=222'
|
22
|
+
# ]
|
23
|
+
# parse_from_response cookies
|
24
|
+
# # => {'aaa' => 111, 'bbb' => 222}
|
25
|
+
#
|
26
|
+
# @example Parse with `cookie_hash`.
|
27
|
+
# cookie_hash = {'ccc' => 333}
|
28
|
+
# parse_from_request 'aaa=111; bbb=222', cookie_hash
|
29
|
+
# cookie_hash
|
30
|
+
# # => {'aaa' => 1, 'bbb' => 2, 'ccc' => 333}
|
31
|
+
def parse_from_request cookies, cookie_hash = {}
|
32
|
+
# Retrieve from hash
|
33
|
+
if cookies.is_a? Hash
|
34
|
+
cookie_hash.merge! cookies
|
35
|
+
return cookie_hash
|
36
|
+
end
|
37
|
+
|
38
|
+
# Extract from string
|
39
|
+
cookies = cookies.split '; ' if cookies.is_a? String
|
40
|
+
|
41
|
+
# Extract from array
|
42
|
+
cookies&.each do |raw_cookie|
|
43
|
+
key, value = raw_cookie.split('=', 2)
|
44
|
+
cookie_hash[key] = value
|
45
|
+
end
|
46
|
+
cookie_hash
|
47
|
+
end
|
48
|
+
|
49
|
+
# Parse response cookies on different formats.
|
50
|
+
#
|
51
|
+
# @param [String,Hash,Array] cookies Cookies to parse.
|
52
|
+
# @param [Hash] cookie_hash ({}) External hash to store parsed cookies.
|
53
|
+
#
|
54
|
+
# @return [Hash]
|
55
|
+
#
|
56
|
+
# @example Parse from string
|
57
|
+
# parse_from_response 'aaa=111; bbb=222'
|
58
|
+
# # => {'aaa' => 111, 'bbb' => 222}
|
59
|
+
#
|
60
|
+
# @example Parse from array.
|
61
|
+
# cookies = [
|
62
|
+
# 'aaa=111; Expires=Thu, Jan 01 1970 00:00:00 UTC; path=/',
|
63
|
+
# 'bbb=222; path=/',
|
64
|
+
# 'ccc=333; path=/; expires=Wed, Jan 01 3000 00:00:00 UTC'
|
65
|
+
# ]
|
66
|
+
# parse_from_response cookies
|
67
|
+
# # => {'bbb' => 222, 'ccc' => 333}
|
68
|
+
#
|
69
|
+
# @example Parse with `cookie_hash`.
|
70
|
+
# cookie_hash = {'ccc' => 333}
|
71
|
+
# parse_from_response 'aaa=111; bbb=222', cookie_hash
|
72
|
+
# cookie_hash
|
73
|
+
# # => {'aaa' => 111, 'bbb' => 222, 'ccc' => 333}
|
74
|
+
def parse_from_response cookies, cookie_hash = {}
|
75
|
+
# Retrieve from hash
|
76
|
+
if cookies.is_a? Hash
|
77
|
+
cookie_hash.merge! cookies
|
78
|
+
return cookie_hash
|
79
|
+
end
|
80
|
+
# Retrieve from String
|
81
|
+
cookies = cookies.split '; ' if cookies.is_a? String
|
82
|
+
|
83
|
+
# Extract from array
|
84
|
+
info = cookie = expires = key = value = nil
|
85
|
+
cookies&.each do |raw_cookie|
|
86
|
+
# Extract cookie data
|
87
|
+
key_pair = raw_cookie.scan(/(?:;\s+([^\=]+)=([^;]*))/i) || []
|
88
|
+
cookie = key_pair.inject(Hash.new){|h,i|h[i[0].to_s.downcase] = i[1]; h}
|
89
|
+
cookie[:key], cookie[:value] = raw_cookie.match(/^\s*(?<key>[^\=]+)\=(?<value>[^;]*)/i)&.captures
|
90
|
+
|
91
|
+
# Check cookie expire
|
92
|
+
expires = cookie['expires'].nil? ? nil : Time.parse(cookie['expires'])
|
93
|
+
if !expires.nil? && Time.now > expires
|
94
|
+
cookie_hash.delete cookie[:key]
|
95
|
+
next
|
96
|
+
end
|
97
|
+
|
98
|
+
# Save cookie
|
99
|
+
cookie_hash[cookie[:key]] = cookie[:value]
|
100
|
+
end
|
101
|
+
cookie_hash
|
102
|
+
end
|
103
|
+
|
104
|
+
# Apply request and response cookies as a hash.
|
105
|
+
#
|
106
|
+
# @param [String,Array,Hash] request_cookies Cookies to parse.
|
107
|
+
# @param [String,Array,Hash] response_cookies Cookies to parse.
|
108
|
+
#
|
109
|
+
# @return [Hash]
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# request_cookies = 'aaa=111; ddd=444'
|
113
|
+
# response_cookies = [
|
114
|
+
# 'aaa=111; Expires=Thu, Jan 01 1970 00:00:00 UTC; path=/',
|
115
|
+
# 'bbb=222; path=/',
|
116
|
+
# 'ccc=333; path=/; expires=Wed, Jan 01 3000 00:00:00 UTC'
|
117
|
+
# ]
|
118
|
+
# update_as_hash , response_cookies
|
119
|
+
# # => {'bbb' => 222, 'ccc' => 333, 'ddd' => 444}
|
120
|
+
def update_as_hash request_cookies, response_cookies
|
121
|
+
cookie_hash = {}
|
122
|
+
parse_from_request request_cookies, cookie_hash
|
123
|
+
parse_from_response response_cookies, cookie_hash
|
124
|
+
cookie_hash
|
125
|
+
end
|
126
|
+
|
127
|
+
# Encode cookies as request cookie string.
|
128
|
+
#
|
129
|
+
# @param [Hash] cookie_hash Hash with cookies.
|
130
|
+
#
|
131
|
+
# @return [String]
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
# cookie_hash = {
|
135
|
+
# 'aaa' => 111,
|
136
|
+
# 'bbb' => 222
|
137
|
+
# }
|
138
|
+
# encode_to_header cookie_hash
|
139
|
+
# # => 'aaa=111; bbb=222'
|
140
|
+
def encode_to_header cookie_hash
|
141
|
+
cookie_hash.map{|k,v| "#{k}=#{v}"}.join '; '
|
142
|
+
end
|
143
|
+
|
144
|
+
# Apply request and response cookies as a string with request format.
|
145
|
+
#
|
146
|
+
# @param [String,Array,Hash] request_cookies Cookies to parse.
|
147
|
+
# @param [String,Array,Hash] response_cookies Cookies to parse.
|
148
|
+
#
|
149
|
+
# @return [String]
|
150
|
+
#
|
151
|
+
# @example
|
152
|
+
# request_cookies = 'aaa=111; ddd=444'
|
153
|
+
# response_cookies = [
|
154
|
+
# 'aaa=111; Expires=Thu, Jan 01 1970 00:00:00 UTC; path=/',
|
155
|
+
# 'bbb=222; path=/',
|
156
|
+
# 'ccc=333; path=/; expires=Wed, Jan 01 3000 00:00:00 UTC'
|
157
|
+
# ]
|
158
|
+
# update_as_hash , response_cookies
|
159
|
+
# # => 'bbb=222; ccc=333; ddd=444'
|
160
|
+
def update request_cookies, response_cookies
|
161
|
+
cookie_hash = update_as_hash request_cookies, response_cookies
|
162
|
+
encode_to_header cookie_hash
|
163
|
+
end
|
164
|
+
|
165
|
+
# Compare if cookie is included into base cookie
|
166
|
+
#
|
167
|
+
# @param [Hash] base_cookie_hash Hash that represent universe.
|
168
|
+
# @param [Hash] cookie_hash Hash that represents to compare.
|
169
|
+
#
|
170
|
+
# @return [Boolean]
|
171
|
+
#
|
172
|
+
# @example Check a success match.
|
173
|
+
# base_cookie_hash = {
|
174
|
+
# 'aaa' => 111,
|
175
|
+
# 'bbb' => 222,
|
176
|
+
# 'ccc' => 333,
|
177
|
+
# 'ddd' => 444
|
178
|
+
# }
|
179
|
+
# cookie_hash = {
|
180
|
+
# 'bbb' => 222,
|
181
|
+
# 'ddd' => 444
|
182
|
+
# }
|
183
|
+
# include? base_cookie_hash, cookie_hash
|
184
|
+
# # => true
|
185
|
+
#
|
186
|
+
# @example Check with fail match.
|
187
|
+
# base_cookie_hash = {
|
188
|
+
# 'aaa' => 111,
|
189
|
+
# 'bbb' => 222,
|
190
|
+
# 'ccc' => 333,
|
191
|
+
# 'ddd' => 444
|
192
|
+
# }
|
193
|
+
# cookie_hash = {
|
194
|
+
# 'bbb' => 555,
|
195
|
+
# 'ddd' => 444
|
196
|
+
# }
|
197
|
+
# include? base_cookie_hash, cookie_hash
|
198
|
+
# # => false
|
199
|
+
def include? base_cookie_hash, cookie_hash
|
200
|
+
cookie_hash.each do |key, value|
|
201
|
+
return false unless base_cookie_hash.has_key?(key) && base_cookie_hash[key] == value
|
202
|
+
end
|
203
|
+
true
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|