curl_escape 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/README.md +118 -0
- data/Rakefile +11 -0
- data/bench.rb +18 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/curl_escape.gemspec +26 -0
- data/ext/curl_escape/curl_escape.c +44 -0
- data/ext/curl_escape/extconf.rb +11 -0
- data/lib/curl_escape.rb +2 -0
- data/lib/curl_escape/core_ext/cgi.rb +10 -0
- data/lib/curl_escape/version.rb +3 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9e245dcbc587665d607975ad25ca806804c28458
|
4
|
+
data.tar.gz: 88e34847057a483229fef9a6887d2065ebc8ef69
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 414c3cca07d563b8bf429692080f4b5c2b89e3810e2a8bb47c44964400777ec7f64a73c42729f1ce777d364ac87442022d079a9f9b6a68fe5973f9a875e7585f
|
7
|
+
data.tar.gz: 7b503b475257be37c14fe80daf5f0615f0f6bca774dfbb61d70f34ede40605f0dbbc95ad6eb52c5eef2c252f290d0dd828a4b2c7acf7b30ca647571362cc0c33
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# CurlEscape
|
2
|
+
[](https://travis-ci.org/joker1007/curl_escape)
|
3
|
+
|
4
|
+
Fast URL escape by libcurl.
|
5
|
+
|
6
|
+
`CurlEscape.escape` is 5x faster or more than `CGI.escape`.
|
7
|
+
|
8
|
+
The spec of escaping is `CGI.escape` compatible, and this gem has core extension for `CGI.escape`.
|
9
|
+
|
10
|
+
## Motivation
|
11
|
+
`CGI.escape` is used by `#to_query` method that is defined by activesupport.
|
12
|
+
|
13
|
+
And `#to_query` is used by `url_for` helper of Rails.
|
14
|
+
|
15
|
+
I want to speed up `url_for`.
|
16
|
+
|
17
|
+
## Benchmark
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require 'benchmark/ips'
|
21
|
+
require 'cgi'
|
22
|
+
|
23
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
24
|
+
require_relative './lib/curl_escape'
|
25
|
+
|
26
|
+
Benchmark.ips do |x|
|
27
|
+
x.config(time: 15, warmup: 5)
|
28
|
+
x.report("cgi_escape") { CGI.escape("'Stop!' said Fred") }
|
29
|
+
x.report("curl_escape") { CurlEscape.escape("'Stop!' said Fred") }
|
30
|
+
x.compare!
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
```
|
35
|
+
Calculating -------------------------------------
|
36
|
+
cgi_escape 13.791k i/100ms
|
37
|
+
curl_escape 52.251k i/100ms
|
38
|
+
-------------------------------------------------
|
39
|
+
cgi_escape 130.471k (±17.8%) i/s - 1.889M
|
40
|
+
curl_escape 832.501k (± 5.6%) i/s - 12.488M
|
41
|
+
|
42
|
+
Comparison:
|
43
|
+
curl_escape: 832501.4 i/s
|
44
|
+
cgi_escape: 130470.6 i/s - 6.38x slower
|
45
|
+
```
|
46
|
+
|
47
|
+
### `url_for` benchmark
|
48
|
+
```
|
49
|
+
irb(main):005:0> app.dashboard_app_path("hogehoge", {foo: "bar", hoge: "aa", aaa: "aaa", bbb: "bbb", hogehoge: "%&[12]"})
|
50
|
+
=> "/apps/hogehoge/dashboard?aaa=aaa&bbb=bbb&foo=bar&hoge=aa&hogehoge=%25%26%5B12%5D"
|
51
|
+
irb(main):006:0> Benchmark.ips do |x|
|
52
|
+
irb(main):007:1* x.config(time: 15, warmup: 5)
|
53
|
+
irb(main):008:1> x.report("url_for") { app.dashboard_app_path("hogehoge", {foo: "bar", hoge: "aa", aaa: "aaa", bbb: "bbb", hogehoge: "%&[12]"}) }
|
54
|
+
irb(main):009:1> end
|
55
|
+
Calculating -------------------------------------
|
56
|
+
url_for 922.000 i/100ms
|
57
|
+
-------------------------------------------------
|
58
|
+
url_for 9.038k (±19.5%) i/s - 129.080k
|
59
|
+
=> #<Benchmark::IPS::Report:0x007fe017c73a68 @entries=[#<Benchmark::IPS::Report::Entry:0x007fe01b53b9b8 @label="url_for", @microseconds=15008895.1587677, @iterations=129080, @ips=9037.936272156061, @ips_sd=1764, @measurement_cycle=922, @show_total_time=false>], @data=nil>
|
60
|
+
irb(main):010:0> require 'curl_escape/core_ext/cgi'
|
61
|
+
=> true
|
62
|
+
irb(main):011:0> app.dashboard_app_path("hogehoge", {foo: "bar", hoge: "aa", aaa: "aaa", bbb: "bbb", hogehoge: "%&[12]"})
|
63
|
+
=> "/apps/hogehoge/dashboard?aaa=aaa&bbb=bbb&foo=bar&hoge=aa&hogehoge=%25%26%5B12%5D"
|
64
|
+
irb(main):012:0>
|
65
|
+
irb(main):013:0* Benchmark.ips do |x|
|
66
|
+
irb(main):014:1* x.config(time: 15, warmup: 5)
|
67
|
+
irb(main):015:1> x.report("url_for") { app.dashboard_app_path("hogehoge", {foo: "bar", hoge: "aa", aaa: "aaa", bbb: "bbb", hogehoge: "%&[12]"}) }
|
68
|
+
irb(main):016:1> end
|
69
|
+
Calculating -------------------------------------
|
70
|
+
url_for 1.192k i/100ms
|
71
|
+
-------------------------------------------------
|
72
|
+
url_for 12.170k (±14.2%) i/s - 177.608k
|
73
|
+
=> #<Benchmark::IPS::Report:0x007fe01b4c8da0 @entries=[#<Benchmark::IPS::Report::Entry:0x007fe015863560 @label="url_for", @microseconds=15003959.655761719, @iterations=177608, @ips=12170.236970422775, @ips_sd=1723, @measurement_cycle=1192, @show_total_time=false>], @data=nil>
|
74
|
+
```
|
75
|
+
|
76
|
+
about 34% faster.
|
77
|
+
|
78
|
+
But the fewer parameters, the less difference.
|
79
|
+
|
80
|
+
## Requirements
|
81
|
+
- curl
|
82
|
+
|
83
|
+
## Installation
|
84
|
+
|
85
|
+
Add this line to your application's Gemfile:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
gem 'curl_escape'
|
89
|
+
```
|
90
|
+
|
91
|
+
And then execute:
|
92
|
+
|
93
|
+
$ bundle
|
94
|
+
|
95
|
+
Or install it yourself as:
|
96
|
+
|
97
|
+
$ gem install curl_escape
|
98
|
+
|
99
|
+
## Usage
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
CurlEscape.escape('Escape target string % あいうえお')
|
103
|
+
# => "Escape+target+string+%25+%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A"
|
104
|
+
|
105
|
+
require 'curl_escape/core_ext/cgi'
|
106
|
+
CGI.escape('Escape target string % あいうえお') # replace implementation
|
107
|
+
```
|
108
|
+
|
109
|
+
## Development
|
110
|
+
|
111
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
112
|
+
|
113
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
114
|
+
|
115
|
+
## Contributing
|
116
|
+
|
117
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/joker1007/curl_escape.
|
118
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/extensiontask"
|
3
|
+
require "rspec/core/rake_task"
|
4
|
+
|
5
|
+
Rake::ExtensionTask.new('curl_escape') do |ext|
|
6
|
+
ext.lib_dir = 'lib/curl_escape'
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
|
11
|
+
task :default => [:compile, :spec]
|
data/bench.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'benchmark/ips'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
5
|
+
require_relative './lib/curl_escape'
|
6
|
+
|
7
|
+
Benchmark.ips do |x|
|
8
|
+
x.config(time: 15, warmup: 5)
|
9
|
+
x.report("cgi_escape") { CGI.escape("'Stop!' said Fred") }
|
10
|
+
x.report("curl_escape") { CurlEscape.escape("'Stop!' said Fred") }
|
11
|
+
x.compare!
|
12
|
+
end
|
13
|
+
|
14
|
+
p CGI.escape("'Stop!' said~Fred foo~~hoge")
|
15
|
+
p CurlEscape.escape("'Stop!' said~Fred foo~~hoge")
|
16
|
+
|
17
|
+
p CGI.escape("'日本語あいうえお")
|
18
|
+
p CurlEscape.escape("'日本語あいうえお")
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "curl_escape"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/curl_escape.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'curl_escape/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "curl_escape"
|
8
|
+
spec.version = CurlEscape::VERSION
|
9
|
+
spec.authors = ["joker1007"]
|
10
|
+
spec.email = ["kakyoin.hierophant@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Fast url escaping by libcurl}
|
13
|
+
spec.description = %q{Fast url escaping by libcurl}
|
14
|
+
spec.homepage = "https://github.com/joker1007/curl_escape"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
spec.extensions = ["ext/curl_escape/extconf.rb"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rake-compiler"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#include <string.h>
|
2
|
+
#include <curl/curl.h>
|
3
|
+
#include <ruby.h>
|
4
|
+
|
5
|
+
VALUE ruby_curl_escape(VALUE self, VALUE str) {
|
6
|
+
int rest, cnt;
|
7
|
+
VALUE output;
|
8
|
+
|
9
|
+
static CURL *curl;
|
10
|
+
if (!curl) {
|
11
|
+
curl = curl_easy_init();
|
12
|
+
}
|
13
|
+
|
14
|
+
char *cStr = StringValueCStr(str);
|
15
|
+
char *cOutput = curl_easy_escape(curl, cStr, strlen(cStr));
|
16
|
+
|
17
|
+
if (cOutput) {
|
18
|
+
for (cnt = 0; *(cOutput + cnt) != '\0'; cnt++) {
|
19
|
+
if (strncmp(cOutput + cnt, "%20", 3) == 0) {
|
20
|
+
*(cOutput + cnt) = '+';
|
21
|
+
rest = strlen(cOutput + cnt + 3);
|
22
|
+
memmove(cOutput + cnt + 1, cOutput + cnt + 3, rest);
|
23
|
+
*(cOutput + cnt + 1 + rest) = '\0';
|
24
|
+
} else if (*(cOutput + cnt) == '~') {
|
25
|
+
cOutput = realloc(cOutput, strlen(cOutput) + 2);
|
26
|
+
rest = strlen(cOutput + cnt + 1);
|
27
|
+
memmove(cOutput + cnt + 3, cOutput + cnt + 1, rest);
|
28
|
+
*(cOutput + cnt + 3 + rest) = '\0';
|
29
|
+
memcpy(cOutput + cnt, "%7E", 3);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
output = rb_str_new2(cOutput);
|
34
|
+
curl_free(cOutput);
|
35
|
+
return output;
|
36
|
+
} else {
|
37
|
+
return Qnil;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
void Init_curl_escape(void) {
|
42
|
+
VALUE module = rb_define_module("CurlEscape");
|
43
|
+
rb_define_singleton_method(module, "escape", ruby_curl_escape, 1);
|
44
|
+
}
|
data/lib/curl_escape.rb
ADDED
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: curl_escape
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- joker1007
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake-compiler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description: Fast url escaping by libcurl
|
70
|
+
email:
|
71
|
+
- kakyoin.hierophant@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions:
|
74
|
+
- ext/curl_escape/extconf.rb
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".travis.yml"
|
80
|
+
- Gemfile
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- bench.rb
|
84
|
+
- bin/console
|
85
|
+
- bin/setup
|
86
|
+
- curl_escape.gemspec
|
87
|
+
- ext/curl_escape/curl_escape.c
|
88
|
+
- ext/curl_escape/extconf.rb
|
89
|
+
- lib/curl_escape.rb
|
90
|
+
- lib/curl_escape/core_ext/cgi.rb
|
91
|
+
- lib/curl_escape/version.rb
|
92
|
+
homepage: https://github.com/joker1007/curl_escape
|
93
|
+
licenses: []
|
94
|
+
metadata: {}
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 2.5.1
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: Fast url escaping by libcurl
|
115
|
+
test_files: []
|