iuri 1.0.0 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f823ae8478599ae553df7854ab74819fd56e1301
4
- data.tar.gz: 81dc21e0b3899b2ddd6908f95fc5d0919e6ee861
3
+ metadata.gz: 80c50f10a15c87f8aedd47924a82bd4069c1a9e3
4
+ data.tar.gz: a78f253736108f72b6b27bdae2ace3563859e6d5
5
5
  SHA512:
6
- metadata.gz: 131316b2a076b97a9d386651a9aa92f24f4f50506b9507b311c3956d06ddba0273836b6f7d03b6d981d9b49e2065f504404dc8f8de608e39ab7586c90668e7b5
7
- data.tar.gz: 8b59b357b357509a98cf600e1e2b80133a7b3aefdf10eb27259bf73c9b67fa7f17e926e3fd6d29b90f4a7d752f8c366e63f49a6faa7b47681ab030800e974bf0
6
+ metadata.gz: 8c904845ebc55971e9f3d968e49b5b1b28a088d97db83ed20477f144e19e608d0057e51bbbdcebea703ce0eb1e9b05509942cac4cd7ad57494be1b92e3742500
7
+ data.tar.gz: 015553c5aa28b0aa769f498b33ccadb870792272a0acbcb229719aa55928dd1c48bf92fab889a6a9640cd5fa3afe437f2270dce6502e8ace1d5fdb9bc131ad04
@@ -0,0 +1,3 @@
1
+ rvm:
2
+ - "2.1.2"
3
+ - "2.1.3"
data/README.md CHANGED
@@ -1,42 +1,158 @@
1
1
  # IURI
2
2
 
3
- Build complex URIs with chainability and immutability. If you're familiar
4
- with URI then you already know how to use it.
3
+ [![Build Status](https://travis-ci.org/tatey/iuri.svg?branch=master)](https://travis-ci.org/tatey/iuri)
4
+
5
+ Build complex URIs with chainability and immutability. No string
6
+ concatenation required. If you're familiar with `URI` then you already know
7
+ how to use it.
8
+
9
+ First it starts like this.
10
+
11
+ ``` ruby
12
+ "https://lifx.co/api/v1/devices".
13
+ ```
14
+
15
+ Then you need to target different hosts in development, staging and
16
+ production.
17
+
18
+ ``` ruby
19
+ "#{ENV['API_SCHEME']}://#{ENV['API_HOST']}/api/v1/devices"
20
+ ```
21
+
22
+ Then staging becomes protected by basic authentication.
23
+
24
+ ``` ruby
25
+ if ENV['API_CREDENTIALS']
26
+ "#{ENV['API_SCHEME']}://#{ENV['API_CREDENTIALS']}@#{ENV['API_HOST']}/api/v1/devices"
27
+ else
28
+ "#{ENV['API_SCHEME']}://#{ENV['API_HOST']}/api/v1/devices"
29
+ end
30
+ ```
31
+
32
+ Then you need to target different paths.
33
+
34
+ ``` ruby
35
+ def devices_url
36
+ base_url + '/api/v1/devices'
37
+ end
38
+
39
+ def accounts_url
40
+ base_url + '/api/v1/accounts'
41
+ end
42
+
43
+ def base_url
44
+ if ENV['API_CREDENTIALS']
45
+ "#{ENV['API_SCHEME']}://#{ENV['API_CREDENTIALS']}@#{ENV['API_HOST']}"
46
+ else
47
+ "#{ENV['API_SCHEME']}://#{ENV['API_HOST']}"
48
+ end
49
+ end
50
+ ```
51
+
52
+ Now you've added three environment variables and you're vulnerable to
53
+ developers mistyping URLs. With `IURI` there's a better way.
54
+
55
+ ``` ruby
56
+ # Development
57
+ # ENV['API_BASE_URL'] = 'http://lifx.dev'
58
+ #
59
+ # Staging
60
+ # ENV['API_BASE_URL'] = 'https://user:pass@staging.lifx.co'
61
+ #
62
+ # Production
63
+ # ENV['API_BASE_URL'] = 'https://lifx.co'
64
+
65
+ def devices_url
66
+ API_BASE_URL.merge(path: "/api/v1/devices")
67
+ end
68
+
69
+ def accounts_url
70
+ API_BASE_URL.merge(path: "/api/v1/accounts")
71
+ end
72
+
73
+ def API_BASE_URL
74
+ IURI.parse(ENV['API_BASE_URL'])
75
+ end
76
+ ```
5
77
 
6
- ## Installation
7
-
8
- Add this line to your application's Gemfile:
9
-
10
- gem 'iuri'
11
-
12
- And then execute:
13
-
14
- $ bundle
78
+ ## Usage
15
79
 
16
- Or install it yourself as:
80
+ Parse URL and append a path.
81
+
82
+ ``` ruby
83
+ uri = IURI.parse("https://user:secret@lifx.co").merge(path: "/api/v1/devices")
84
+ uri.to_s # => "https://user:secret@lifx.co/api/v1/devices"
85
+ ```
86
+
87
+ Preferring components to strings gives you greater flexibility over the
88
+ base URL. Here we include a query string at the end of the URL and change
89
+ the path as required.
90
+
91
+ ``` ruby
92
+ uri = IURI.parse("https://lifx.co?api_key=secret").merge(path: "/api/v1/devices")
93
+ uri.to_s # => "https://lifx.co/api/v1/devices?api_key=secret"
94
+ ```
95
+
96
+ Queries can also be built with a hash avoiding worrying about formatting
97
+ and escaping. Deep hashes are OK.
98
+
99
+ ``` ruby
100
+ uri = IURI.parse("https://lifx.co").merge(params: {api_key: 'secret'})
101
+ uri.to_s # => "https://lifx.co/?api_key=secret"
102
+ ```
103
+
104
+ Supports the same components as `URI`. Here's a sample of commonly used
105
+ components.
106
+
107
+ ``` ruby
108
+ iuri = IURI.parse("https://lifx.co").merge({
109
+ path: "/api/v1/devices"
110
+ query: "api_key=secret"
111
+ user: "user"
112
+ password: "secret"
113
+ })
114
+
115
+ iuri.path # => "/api/v1/devices"
116
+ iuri.query # => "api_key=secret"
117
+ iuri.user # => "user"
118
+ iuri.password # => "secret"
119
+ ```
120
+
121
+ Each `merge` returns a copy guaranteeing that constants and variables
122
+ remain unchanged.
123
+
124
+ ``` ruby
125
+ uri1 = IURI.parse("https://lifx.co")
126
+ uri2 = uri1.merge(path: "/api/v1/devices")
127
+ uri1.to_s # => "https://lifx.co"
128
+ uri2.to_s # => "https://lifx.co/api/v1/devices"
129
+ ```
17
130
 
18
- $ gem install iuri
131
+ ## Installation
19
132
 
20
- ## Usage
133
+ First, add this line to your application's Gemfile.
21
134
 
22
- Change components of a URI using a hash. Changes are chainable and each
23
- one returns a new instance.
135
+ ``` ruby
136
+ gem 'iuri'
137
+ ```
24
138
 
25
- Example:
139
+ Then, then execute.
26
140
 
27
- uri1 = IURI.parse("https://user:secret@lifx.co")
28
- uri2 = uri1.merge(path: "/api/v1/foos")
29
- uri2.to_s # => "https://user:secret@lifx.co/api/v1/foos"
141
+ ```
142
+ $ bundle
143
+ ```
30
144
 
31
145
  ## Tests
32
146
 
33
147
  Run the entire test suite.
34
148
 
35
- $ rake
149
+ ```
150
+ $ rake
151
+ ```
36
152
 
37
153
  ## Contributing
38
154
 
39
- 1. Fork it ( https://github.com/tatey/iuri/fork )
155
+ 1. Fork it (https://github.com/tatey/iuri/fork)
40
156
  2. Create your feature branch (`git checkout -b my-new-feature`)
41
157
  3. Commit your changes (`git commit -am 'Add some feature'`)
42
158
  4. Push to the branch (`git push origin my-new-feature`)
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'bundler/setup'
2
3
  require 'rake/testtask'
3
4
 
4
5
  Rake::TestTask.new :test do |test|
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ['Tate Johnson']
10
10
  spec.email = ['tate@lifx.co']
11
11
  spec.summary = %q{Build complex URIs with chainability and immutability.}
12
- spec.description = %q{Build complex URIs with chainability and immutability.}
13
- spec.homepage = ''
12
+ spec.description = %q{Build complex URIs with chainability and immutability. No string concatenation required.}
13
+ spec.homepage = 'https://github.com/tatey/iuri'
14
14
  spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -19,5 +19,6 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_development_dependency 'bundler', '~> 1.6'
22
+ spec.add_development_dependency 'minitest', '~> 5.4.2'
22
23
  spec.add_development_dependency 'rake'
23
24
  end
@@ -1,40 +1,69 @@
1
+ require 'delegate'
1
2
  require 'uri'
2
3
  require 'iuri/version'
3
4
 
4
- class IURI
5
- def initialize(uri)
6
- @uri = uri
7
- end
8
-
5
+ module IURI
9
6
  def self.parse(string)
10
7
  uri = URI.parse(string)
11
- new(uri)
8
+ Generic.new(uri)
12
9
  end
13
10
 
14
- # Change components of a URI using a hash. Changes are chainable and
15
- # each one returns a new instance.
16
- #
17
- # Example:
18
- # uri1 = MergeableURI.parse("https://lifx.co")
19
- # uri2 = uri1.merge(path: "/foo/bar")
20
- # uri2.to_s # => "https://lifx.co/foo/bar"
21
- #
22
- # @param options [Hash] Components
23
- # @return [MergeableURI] A new instance
24
- def merge(options)
25
- copy = @uri.dup
26
- options.each do |key, value|
27
- writer = :"#{key}="
28
- if copy.respond_to?(writer)
29
- copy.send(writer, value)
11
+ class Generic < SimpleDelegator
12
+ # Change components of a URI using a hash. Changes are chainable and
13
+ # each one returns a new instance.
14
+ #
15
+ # Example:
16
+ # uri1 = IURI.parse("https://lifx.co")
17
+ # uri2 = uri1.merge(path: "/foo/bar")
18
+ # uri2.to_s # => "https://lifx.co/foo/bar"
19
+ #
20
+ # @param options [Hash] Components
21
+ # @return [URI] A new instance
22
+ def merge(components)
23
+ copy = clone
24
+ components.each do |key, value|
25
+ writer = :"#{key}="
26
+ if copy.respond_to?(writer)
27
+ copy.send(writer, value)
28
+ else
29
+ raise KeyError, "key not found: \"#{key}\""
30
+ end
31
+ end
32
+ copy
33
+ end
34
+
35
+ def params=(new_params)
36
+ self.query = build_nested_query(new_params)
37
+ end
38
+
39
+ def inspect
40
+ super.sub('#<URI', '#<IURI')
41
+ end
42
+
43
+ private
44
+
45
+ # A special thanks to rack for this one.
46
+ # See https://github.com/rack/rack/blob/e98a9f7ef0ddd9589145ea953948c73a8ce3caa9/lib/rack/utils.rb
47
+ def build_nested_query(value, prefix = nil)
48
+ case value
49
+ when Array
50
+ value.map { |v|
51
+ build_nested_query(v, "#{prefix}[]")
52
+ }.join("&")
53
+ when Hash
54
+ value.map { |k, v|
55
+ build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
56
+ }.reject(&:empty?).join('&')
57
+ when nil
58
+ prefix
30
59
  else
31
- raise KeyError, "key not found: \"#{key}\""
60
+ raise ArgumentError, "value must be a Hash" if prefix.nil?
61
+ "#{prefix}=#{escape(value)}"
32
62
  end
33
63
  end
34
- self.class.new(copy)
35
- end
36
64
 
37
- def to_s
38
- @uri.to_s
65
+ def escape(value)
66
+ URI.encode_www_form_component(value)
67
+ end
39
68
  end
40
69
  end
@@ -1,3 +1,3 @@
1
- class IURI
2
- VERSION = '1.0.0'
1
+ module IURI
2
+ VERSION = '1.1.0'
3
3
  end
@@ -2,23 +2,45 @@ require 'minitest/autorun'
2
2
  require 'iuri'
3
3
 
4
4
  class IURITest < Minitest::Test
5
- def test_it_sets_known_components
5
+ def test_setting_known_components
6
6
  uri1 = IURI.parse('http://lifx.co')
7
7
  uri2 = uri1.merge(scheme: 'https', path: '/foo/bar', query: 'baz=true')
8
8
 
9
9
  assert_equal 'https://lifx.co/foo/bar?baz=true', uri2.to_s
10
10
  end
11
11
 
12
- def test_it_raises_unknown_components
12
+ def test_setting_unknown_components_raises_key_error
13
13
  assert_raises(KeyError) do
14
14
  IURI.parse('http://lifx.co').merge(combobulator: 42)
15
15
  end
16
16
  end
17
17
 
18
- def test_it_is_a_copy
18
+ def test_setting_params
19
+ uri1 = IURI.parse('http://lifx.co')
20
+ uri2 = uri1.merge(params: {a: '1', b: ['1', '2', '3'], c: {d: '1'}})
21
+
22
+ assert_equal 'http://lifx.co?a=1&b[]=1&b[]=2&b[]=3&c[d]=1', uri2.to_s
23
+ end
24
+
25
+ def test_getting_known_components
26
+ uri = IURI.parse('http://lifx.co/foo/bar?baz=true')
27
+
28
+ assert uri.scheme, 'http'
29
+ assert uri.host, 'lifx.co'
30
+ assert uri.path, '/foo/bar'
31
+ assert uri.query, 'baz=true'
32
+ end
33
+
34
+ def test_merge_returns_copy
19
35
  uri1 = IURI.parse('http://lifx.co')
20
36
  uri2 = uri1.merge(path: '/foo/bar')
21
37
 
22
38
  refute_same uri1, uri2
23
39
  end
40
+
41
+ def test_inspect
42
+ uri = IURI.parse('http://lifx.co')
43
+
44
+ assert_match /\A#<IURI/, uri.inspect
45
+ end
24
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iuri
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tate Johnson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-16 00:00:00.000000000 Z
11
+ date: 2014-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 5.4.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 5.4.2
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,7 +52,8 @@ dependencies:
38
52
  - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
41
- description: Build complex URIs with chainability and immutability.
55
+ description: Build complex URIs with chainability and immutability. No string concatenation
56
+ required.
42
57
  email:
43
58
  - tate@lifx.co
44
59
  executables: []
@@ -46,6 +61,7 @@ extensions: []
46
61
  extra_rdoc_files: []
47
62
  files:
48
63
  - ".gitignore"
64
+ - ".travis.yml"
49
65
  - Gemfile
50
66
  - LICENSE.txt
51
67
  - README.md
@@ -54,7 +70,7 @@ files:
54
70
  - lib/iuri.rb
55
71
  - lib/iuri/version.rb
56
72
  - test/iuri_test.rb
57
- homepage: ''
73
+ homepage: https://github.com/tatey/iuri
58
74
  licenses:
59
75
  - MIT
60
76
  metadata: {}
@@ -80,4 +96,3 @@ specification_version: 4
80
96
  summary: Build complex URIs with chainability and immutability.
81
97
  test_files:
82
98
  - test/iuri_test.rb
83
- has_rdoc: