querystring 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2@querystring
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Bob Corsaro
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,161 @@
1
+ = querystring
2
+
3
+ A small and flexible library to parse and create HTTP query strings.
4
+
5
+ Many languages, libraries and application use different styles of query
6
+ strings. Specifically, query arrays seem to take on many different forms
7
+ accross the web. Some APIs use multiple name/value pairs with the same name to
8
+ represent arrays. Others use the '[]' notation, and some even include an index
9
+ in the brackets. Other APIs use a comma seperated list of values, with only
10
+ one name parameter. querystring is meant to be flexible enough to create and
11
+ parse in any style.
12
+
13
+ == Usage
14
+
15
+ QueryString provides stringify and parse methods. Both methods take an optional
16
+ hash as a second parameter defining the behavior of the function.
17
+
18
+ === Stringify
19
+
20
+ Default stringify options::
21
+ {
22
+ :seperator => '&', # between params
23
+ :equals => '=', # between key/value pairs
24
+ :array_style => :seperate, # or :combine
25
+ :array_brackets => false, # use [] with array_style :seperate
26
+ :array_index => false, # use indexes with array style :seperate
27
+ :array_seperator => ',' # used with :combine array style
28
+ }
29
+
30
+ The array_ options need some explaining. For style, :seperated means that each
31
+ element in the array will get it's own name/value pair. Combined means that
32
+ they will be combined into one name/value pair.
33
+
34
+ For seperate style, brackets is used to determine if '[]' should be appended to
35
+ each name/value pair. If index is specified, then the index number will be put
36
+ inside the brackets, or appended to the name if brackets is false.
37
+
38
+ For combined style, we have the seperator option. seperator is used to determine
39
+ how they will be combined.
40
+
41
+ === Parse
42
+
43
+ Parse always parses into arrays for simplicities sake. Every value is an array.
44
+
45
+ == Examples
46
+
47
+ >> ########################
48
+ >> # stringify
49
+ >> ########################
50
+ >>
51
+ >> require 'querystring'
52
+ >>
53
+ >> obj = {
54
+ :name => 'bob',
55
+ :roles => [
56
+ 'maintainer',
57
+ 'contributor'
58
+ ],
59
+ :homepage => 'http://www.google.com/profiles/rcorsaro'
60
+ }
61
+ >>
62
+ >> puts QueryString.stringify(obj)
63
+ name=bob&roles=maintainer&roles=contributor&homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro
64
+ >>
65
+ >> puts QueryString.stringify(obj, {:seperator => '*'})
66
+ name=bob*roles=maintainer*roles=contributor*homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro
67
+ >>
68
+ >> puts QueryString.stringify(obj, {:array_brackets => true})
69
+ name=bob&roles[]=maintainer&roles[]=contributor&homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro
70
+ >>
71
+ >> puts QueryString.stringify(obj, {:array_brackets => true, :array_index => true})
72
+ name=bob&roles[0]=maintainer&roles[1]=contributor&homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro
73
+ >>
74
+ >> puts QueryString.stringify(obj, {:array_index => true})
75
+ name=bob&roles0=maintainer&roles1=contributor&homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro
76
+ >>
77
+ >> puts QueryString.stringify(obj, {:array_style => :combined})
78
+ name=bob&roles=maintainer,contributor&homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro
79
+ >>
80
+ >> # Be careful with this because we do no check to make sure your seperator is sane.
81
+ >> # '+' would usually be a bad choice since values can potentially have a space in
82
+ >> # them, which is converted to '+' when encoded. But you know what you doing, so
83
+ >> # we let you go about your work.
84
+ >> puts QueryString.stringify(obj, {:array_style => :combined, :array_seperator => '!'})
85
+ name=bob&roles=maintainer!contributor
86
+ >>
87
+ >> ########################
88
+ >> # stringify
89
+ >> ########################
90
+ >>
91
+ >> require 'ap'
92
+ >>
93
+ >> ap QueryString.parse('name=bob&roles=maintainer&roles=contributor&homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro')
94
+ {
95
+ "name" => [
96
+ [0] "bob",
97
+ ],
98
+ "roles => [
99
+ [0] "maintainer",
100
+ [1] "contributor"
101
+ ],
102
+ "homepage" => [
103
+ [0] "http://www.google.com/profiles/rcorsaro"
104
+ }
105
+ >> ap QueryString.parse('name=bob*roles=maintainer*roles=contributor*homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro', :seperator => '*')
106
+ {
107
+ "name" => [
108
+ [0] "bob",
109
+ ],
110
+ "roles => [
111
+ [0] "maintainer",
112
+ [1] "contributor"
113
+ ],
114
+ "homepage" => [
115
+ [0] "http://www.google.com/profiles/rcorsaro"
116
+ }
117
+ >> ap QueryString.parse('name=bob&roles[]=maintainer&roles[]=contributor&homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro')
118
+ {
119
+ "name" => [
120
+ [0] "bob",
121
+ ],
122
+ "roles => [
123
+ [0] "maintainer",
124
+ [1] "contributor"
125
+ ],
126
+ "homepage" => [
127
+ [0] "http://www.google.com/profiles/rcorsaro"
128
+ }
129
+ >> ap QueryString.parse('name=bob&roles[0]=maintainer&roles[1]=contributor&homepage=http%3a%2f%2fwww.google.com%2fprofiles%2frcorsaro')
130
+ {
131
+ "name" => [
132
+ [0] "bob",
133
+ ],
134
+ "roles => [
135
+ [0] "maintainer",
136
+ [1] "contributor"
137
+ ],
138
+ "homepage" => [
139
+ [0] "http://www.google.com/profiles/rcorsaro"
140
+ }
141
+
142
+
143
+
144
+
145
+
146
+
147
+ == Contributing to querystring
148
+
149
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
150
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
151
+ * Fork the project
152
+ * Start a feature/bugfix branch
153
+ * Commit and push until you are happy with your contribution
154
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
155
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
156
+
157
+ == Copyright
158
+
159
+ Copyright (c) 2011 Bob Corsaro. See LICENSE.txt for
160
+ further details.
161
+
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "querystring"
16
+ gem.homepage = "http://github.com/dokipen/ruby-querystring"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Final solution for HTTP querystrings}
19
+ gem.description = %Q{Flexible querystring generator}
20
+ gem.email = "bob@embed.ly"
21
+ gem.authors = ["Bob Corsaro"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "querystring #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,67 @@
1
+ require 'cgi'
2
+
3
+ module QueryString
4
+ VERSION = File.read(File.expand_path('../../VERSION', __FILE__)).strip
5
+
6
+ def self.stringify obj, options={}
7
+ o = {
8
+ :seperator => '&', # between params
9
+ :equals => '=', # between key/value pairs
10
+ :array_style => :seperate, # or :combine
11
+ :array_brackets => false, # use [] with array_style :seperate
12
+ :array_index => false, # use indexes with array style :seperate
13
+ :array_seperator => ',' # used with :combine array style
14
+ }.merge(options)
15
+
16
+ # used for seperate style arrays
17
+ ar_tmpl = "%s#{'[' if o[:array_brackets]}%s#{']' if o[:array_brackets]}#{o[:equals]}%s"
18
+
19
+ obj.map do |key,value|
20
+ key = CGI.escape(key.to_s)
21
+
22
+ if value.is_a?Array
23
+ case o[:array_style]
24
+ when :combine
25
+ list = value.map do |inner_value|
26
+ CGI.escape(inner_value.to_s)
27
+ end.join o[:array_seperator]
28
+ "#{key}#{o[:equals]}#{list}"
29
+ else # when :seperate
30
+ value.each_with_index.map do |inner_value, index|
31
+ index = o[:array_index] ? index.to_s : ''
32
+ inner_value = CGI.escape(inner_value.to_s)
33
+
34
+ ar_tmpl%[key, index, inner_value]
35
+ end.join o[:seperator]
36
+ end
37
+ else
38
+ value = CGI.escape(value.to_s)
39
+
40
+ "#{key}#{o[:equals]}#{value}"
41
+ end
42
+ end.join o[:seperator]
43
+ end
44
+
45
+ def self.parse q, options={}
46
+ o = {
47
+ :seperator => /&|;/, # between params
48
+ :equals => '=', # between key/value pairs
49
+ :array_seperator => ',' # used with :combine array style
50
+ }.merge(options)
51
+
52
+ q.split(o[:seperator]).inject({}) do |ret, pair|
53
+ key, value = pair.split(o[:equals])
54
+ value.split(o[:array_seperator]).inject(ret) do |ret, part|
55
+ key =~ /([^\[]+)(\[(\d)?\])?/
56
+ ret[$1] ||= []
57
+ if $3
58
+ ret[$1][$3.to_i] = CGI.unescape(part)
59
+ else
60
+ ret[$1] << CGI.unescape(part)
61
+ end
62
+ ret
63
+ end
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path('../../lib', __FILE__))
3
+ %w{querystring test/unit}.each{|i| require i}
4
+
5
+ class QueryStringTest < Test::Unit::TestCase
6
+ include QueryString
7
+
8
+ # shorthand parse
9
+ def p *a
10
+ QueryString.parse *a
11
+ end
12
+
13
+ def test_parse
14
+ # testing object
15
+ expected = {
16
+ "a" => ["1"],
17
+ "b" => ["2","3","4",'http://www.google.com/hello?far=near&war=peace']
18
+ }
19
+
20
+ queries = [
21
+ p('a=1&b[0]=2&b[1]=3&b[2]=4&b[3]=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace'),
22
+ # p('a=1&b0=2&b1=3&b2=4&b3=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace'), fuck this
23
+ p('a=1&b[]=2&b[]=3&b[]=4&b[]=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace'),
24
+ p('a=1&b=2&b=3&b=4&b=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace'),
25
+ p('a=1|b=2|b=3|b=4|b=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace', {:seperator => '|'}),
26
+ p('a~1&b~2&b~3&b~4&b~http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace', {:equals => '~'}),
27
+ p('a=1&b=2,3,4,http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace'),
28
+ p('a=1&b=2|3|4|http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace', {:array_seperator => '|'})
29
+ ]
30
+
31
+ queries.each do |i|
32
+ assert_equal(expected,i)
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path('../../lib', __FILE__))
3
+ %w{querystring test/unit}.each{|i| require i}
4
+
5
+ class QueryStringTest < Test::Unit::TestCase
6
+ include QueryString
7
+
8
+ # shorthand stringify
9
+ def s *a
10
+ QueryString.stringify *a
11
+ end
12
+
13
+ def test_stringify
14
+ # testing object
15
+ o = {
16
+ :a => 1,
17
+ :b => [2,3,4,'http://www.google.com/hello?far=near&war=peace']
18
+ }
19
+
20
+ queries = {
21
+ s(o, :array_brackets => true, :array_index => true) =>
22
+ 'a=1&b[0]=2&b[1]=3&b[2]=4&b[3]=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace',
23
+ s(o, :array_brackets => false, :array_index => true) =>
24
+ 'a=1&b0=2&b1=3&b2=4&b3=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace',
25
+ s(o, :array_brackets => true, :array_index => false) =>
26
+ 'a=1&b[]=2&b[]=3&b[]=4&b[]=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace',
27
+ s(o) =>
28
+ 'a=1&b=2&b=3&b=4&b=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace',
29
+ s(o, :seperator => '|') =>
30
+ 'a=1|b=2|b=3|b=4|b=http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace',
31
+ s(o, :equals => '~') =>
32
+ 'a~1&b~2&b~3&b~4&b~http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace',
33
+ s(o, :array_style => :combine) =>
34
+ 'a=1&b=2,3,4,http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace',
35
+ s(o, :array_style => :combine, :array_seperator => '.') =>
36
+ 'a=1&b=2.3.4.http%3A%2F%2Fwww.google.com%2Fhello%3Ffar%3Dnear%26war%3Dpeace'
37
+ }
38
+
39
+ queries.each do |k,v|
40
+ assert_equal(v,k)
41
+ end
42
+ end
43
+
44
+ def test_version
45
+ assert_not_nil(QueryString::VERSION)
46
+ end
47
+ end
48
+
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: querystring
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bob Corsaro
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-03-27 00:00:00.000000000 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: shoulda
17
+ requirement: &67906090 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *67906090
26
+ - !ruby/object:Gem::Dependency
27
+ name: bundler
28
+ requirement: &67903430 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *67903430
37
+ - !ruby/object:Gem::Dependency
38
+ name: jeweler
39
+ requirement: &67902200 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 1.5.2
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *67902200
48
+ - !ruby/object:Gem::Dependency
49
+ name: rcov
50
+ requirement: &67873920 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *67873920
59
+ description: Flexible querystring generator
60
+ email: bob@embed.ly
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files:
64
+ - LICENSE.txt
65
+ - README.rdoc
66
+ files:
67
+ - .rvmrc
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.rdoc
71
+ - Rakefile
72
+ - VERSION
73
+ - lib/querystring.rb
74
+ - test/test_parse.rb
75
+ - test/test_stringify.rb
76
+ has_rdoc: true
77
+ homepage: http://github.com/dokipen/ruby-querystring
78
+ licenses:
79
+ - MIT
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ segments:
91
+ - 0
92
+ hash: -47907889
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 1.6.2
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Final solution for HTTP querystrings
105
+ test_files:
106
+ - test/test_parse.rb
107
+ - test/test_stringify.rb