slice-ruby 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4ba0c0ad115c43862e724220ecb9de82bbf4e945
4
+ data.tar.gz: 33167ae57e9c4bd5172534dd9ff8135c77ca640b
5
+ SHA512:
6
+ metadata.gz: e5a6fbb27f75bf8f48a10b40097ff2402f1d5a824e33ff9d60c0a9145b53712b65459bce735f22373a3cb89ce68f013038be0435da9e3db5c28bea3768f06bb4
7
+ data.tar.gz: 840b0bd98254b2cc86a55eadb81029397e4f421f0a6e69acacfd17fd2c3ad90bbc9b0ced813104f7bdf6b48cfc75b5812c91646c98897d19398490c8171072a6
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in slice.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Naoki Orii
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ all: test doc
2
+
3
+ doc:
4
+ git grep -h "^\s\+# \?" lib/slice/response.rb | sed -E 's; +# ?;;' > doc/response.md
5
+ git grep -h "^\s\+# \?" lib/slice/client.rb | sed -E 's; +# ?;;' > doc/client.md
6
+ git grep -h "^\s\+# \?" lib/slice/resource_based_methods.rb | sed -E 's; +# ?;;' >> doc/client.md
7
+
8
+ release:
9
+ bundle exec rake release
10
+
11
+ setup:
12
+ gem install bundler
13
+ bundle install
14
+
15
+ test:
16
+ bundle exec rspec
17
+
18
+ .PHONY: doc release setup test
@@ -0,0 +1,102 @@
1
+ # slice-ruby
2
+
3
+ A Ruby interface to the Slice API
4
+
5
+ ## Quick start
6
+
7
+ Install via Rubygems
8
+
9
+ `gem install slice-ruby`
10
+
11
+ ... or add to your Gemfile
12
+
13
+ `gem "slice-ruby", "~> 0.1"`
14
+
15
+ ## Sample Usage
16
+
17
+ ```ruby
18
+ require 'slice'
19
+
20
+ oauth = Slice::OAuth.new(client_id, client_secret, redirect_url)
21
+ auth_url = oauth.generate_auth_url
22
+
23
+ access_token = oauth.authenticate! auth_code
24
+
25
+ client = Slice::Client.new(access_token: access_token.token)
26
+ client.list_items
27
+ client.list_orders
28
+ client.create_order(orderTitle: 'Your Amazon.com order', ...)
29
+ client.get_order(123)
30
+ client.update_order(123, orderTotal: 395, ...)
31
+ client.list_items(limit: 3, offset: 10)
32
+ client.list_items(limit: 3, offset: 10).status
33
+ client.list_items(limit: 3, offset: 10).headers
34
+ client.list_items(limit: 3, offset: 10).body
35
+ ```
36
+
37
+ See [doc/client.md](doc/client.md) for more details
38
+
39
+ Also, note that `access_token` is a `OAuth2::AccessToken` object from [intridea/oauth2](https://github.com/intridea/oauth2), so you can call methods on it such as `access_token.expired?` and `access_token.refresh!`
40
+
41
+ ## CLI Usage
42
+
43
+ You can use the `slice` executable to call `Slice::Client`'s methods.
44
+
45
+ ```
46
+ $ slice <method> <arguments> [headers|params] [options]
47
+ | | | | |
48
+ | | | | `-- -H, --host
49
+ | | | | -a, --access-token
50
+ | | | | -c, --color
51
+ | | | | -h, --help
52
+ | | | | --header
53
+ | | | | --no-body
54
+ | | | |
55
+ | | | `------------ key=value or key:=value
56
+ | | |
57
+ | | `------------------- Key:value
58
+ | |
59
+ | `------------------------------ required arguments for the method
60
+ |
61
+ `----------------------------------------- method name
62
+
63
+
64
+ $ slice list_orders
65
+ $ slice list_merchants
66
+ $ slice list_orders limit=3 offset=2
67
+
68
+ ```
69
+
70
+ ### Method and Arguments
71
+
72
+ Pass [Slice::Client's method name](doc/client.md) and required arguments.
73
+
74
+ ### Access token
75
+
76
+ Accepts access token via `-a, --access-token` or `SLICE_ACCESS_TOKEN` environment variable.
77
+
78
+ ### Headers
79
+
80
+ To set custom request headers, use `Key:value` syntax.
81
+
82
+ ```
83
+ $ slice list_items "Authorization:Bearer 1234567890abcdef1234567890abcdef"
84
+ ```
85
+
86
+ ### Params
87
+
88
+ Params are used for query string in the GET method, or for request body in other methods.
89
+ You can set params by `key=value` or `key:=value` syntax.
90
+ `key=value` is parsed into its String value, while `key:=value` is parsed into its JSON value (e.g. key:=17 will be `{"key":17}`).
91
+ The `slice` executable also accepts params via STDIN.
92
+
93
+ ```
94
+ $ slice list_items page=2 per_page=10
95
+ $ slice create_item < params.json
96
+ ```
97
+
98
+ ![](images/cli.png)
99
+
100
+ ## Acknowledgements
101
+
102
+ A good chunk of the code has been shamelessly taken from [increments/qiita-rb](https://github.com/increments/qiita-rb).
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new("spec")
5
+ task :default => :spec
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
3
+ require "slice"
4
+
5
+ builder = Slice::CommandBuilder.new(ARGV)
6
+ command = builder.call
7
+ command.call
Binary file
@@ -0,0 +1,22 @@
1
+ require "active_support/core_ext/object/blank"
2
+ require "active_support/core_ext/string/inflections"
3
+ require "active_support/core_ext/string/strip"
4
+ require "faraday"
5
+ require "faraday_middleware"
6
+ require "json"
7
+ require "rack/utils"
8
+ require "rainbow"
9
+ require "rouge"
10
+ require "slop"
11
+
12
+ require "slice/arguments"
13
+ require "slice/client"
14
+ require "slice/command_builder"
15
+ require "slice/commands/base"
16
+ require "slice/commands/error"
17
+ require "slice/commands/request"
18
+ require "slice/oauth"
19
+ require "slice/resource_based_methods"
20
+ require "slice/response"
21
+ require "slice/response_renderer"
22
+ require "slice/version"
@@ -0,0 +1,133 @@
1
+ module Slice
2
+ class Arguments
3
+ def initialize(argv)
4
+ @argv = argv
5
+ end
6
+
7
+ def access_token
8
+ slop_options["access-token"] || ENV["SLICE_ACCESS_TOKEN"]
9
+ end
10
+
11
+ def arguments
12
+ parsed_argv_data[:arguments]
13
+ end
14
+
15
+ def color
16
+ slop_options["color"]
17
+ end
18
+
19
+ def error_message
20
+ slop_options.to_s
21
+ end
22
+
23
+ def headers
24
+ parsed_argv_data[:headers]
25
+ end
26
+
27
+ def host
28
+ slop_options["host"]
29
+ end
30
+
31
+ def method_name
32
+ ARGV[0]
33
+ end
34
+
35
+ def params
36
+ params_from_stdin.merge(parsed_argv_data[:params])
37
+ end
38
+
39
+ def show_body
40
+ !slop_options["no-body"]
41
+ end
42
+
43
+ def show_header
44
+ slop_options["header"]
45
+ end
46
+
47
+ def valid?
48
+ has_valid_slop_options? && has_valid_method_name? && has_valid_arguments? && !has_invalid_json_input?
49
+ end
50
+
51
+ private
52
+
53
+ def has_input_from_stdin?
54
+ has_pipe_input? || has_redirect_input?
55
+ end
56
+
57
+ def has_invalid_json_input?
58
+ params_from_stdin
59
+ false
60
+ rescue JSON::ParserError
61
+ true
62
+ end
63
+
64
+ def has_pipe_input?
65
+ File.pipe?(STDIN)
66
+ end
67
+
68
+ def has_redirect_input?
69
+ File.select([STDIN], [], [], 0) != nil
70
+ end
71
+
72
+ def has_valid_arguments?
73
+ -(Client.instance_method(method_name).arity) - 1 == arguments.length
74
+ end
75
+
76
+ def has_valid_method_name?
77
+ !method_name.nil? && Client.instance_methods.include?(method_name.to_sym)
78
+ end
79
+
80
+ def has_valid_slop_options?
81
+ !slop_options["help"]
82
+ rescue
83
+ false
84
+ end
85
+
86
+ def params_from_stdin
87
+ @params_from_stdin ||= begin
88
+ if has_input_from_stdin?
89
+ JSON.parse(STDIN.read)
90
+ else
91
+ {}
92
+ end
93
+ end
94
+ end
95
+
96
+ def parsed_argv_data
97
+ @parsed_argv_data ||= begin
98
+ params = {}
99
+ headers = {}
100
+ arguments = []
101
+ ARGV[1..-1].each do |section|
102
+ case
103
+ when /(?<key>.+):(?<value>[^=]+)/ =~ section
104
+ headers[key] = value
105
+ when /(?<key>.+):=(?<value>.+)/ =~ section
106
+ params[key] = JSON.parse(%<{"key":#{value}}>)["key"]
107
+ when /(?<key>.+)=(?<value>.+)/ =~ section
108
+ params[key] = value
109
+ else
110
+ arguments << section
111
+ end
112
+ end
113
+ {
114
+ arguments: arguments,
115
+ headers: headers,
116
+ params: params,
117
+ }
118
+ end
119
+ end
120
+
121
+ def slop_options
122
+ @slop_options ||= Slop.parse!(@argv) do
123
+ banner "Usage: slice <method> [arguments] [headers|params] [options]"
124
+ on "H", "host=", "Change API server's host"
125
+ on "a", "access-token=", "Access token"
126
+ on "c", "color", "Color output"
127
+ on "h", "help", "Display help message"
128
+ on "header", "Show response header"
129
+ on "no-body", "Hide response body"
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,153 @@
1
+ require "uri"
2
+ require "slice/resource_based_methods"
3
+ require "slice/version"
4
+
5
+ ## Slice::Client
6
+ # A class for API client to send HTTP requests.
7
+ #
8
+ module Slice
9
+ class Client
10
+ DEFAULT_ACCEPT = "application/json"
11
+
12
+ DEFAULT_HOST = "api.slice.com"
13
+
14
+ DEFAULT_USER_AGENT = "Slice Ruby Gem #{Slice::VERSION}"
15
+
16
+ DEFAULT_HEADERS = {
17
+ "Accept" => DEFAULT_ACCEPT,
18
+ "User-Agent" => DEFAULT_USER_AGENT,
19
+ }
20
+
21
+ include ResourceBasedMethods
22
+
23
+ # ### Slice::Client.new(options = {})
24
+ # Creates a new instance of `Slice::Client` class.
25
+ # `options` can have following key-values:
26
+ #
27
+ # * `access_token` - (String) Access token issued to authenticate and authorize user.
28
+ # * `host` - (String) Hostname where this client accesses to.
29
+ #
30
+ # ```rb
31
+ # Slice::Client.new
32
+ # Slice::Client.new(access_token: "...")
33
+ # ```
34
+ #
35
+ def initialize(access_token: nil, host: nil, ssl: true)
36
+ @access_token = access_token
37
+ @host = host
38
+ @ssl = ssl
39
+ end
40
+
41
+ # ### Slice::Client#get(path, params = nil, headers = nil)
42
+ # Sends GET request with given parameters, then returns a `Slice::Response`.
43
+ # `params` are url-encoded and used as URI query string.
44
+ #
45
+ # ```rb
46
+ # client.get("/api/v1/items", page: 2)
47
+ # ```
48
+ #
49
+ def get(path, params = nil, headers = nil)
50
+ process(:get, path, params, headers)
51
+ end
52
+
53
+ # ### Slice::Client#post(path, params = nil, headers = nil)
54
+ # Sends POST request with given parameters, then returns a Slice::Response.
55
+ # `params` are JSON-encoded and used as request body.
56
+ #
57
+ # ```rb
58
+ # client.post("/api/v1/items", category: "...", price: "...")
59
+ # ```
60
+ #
61
+ def post(path, params = nil, headers = nil)
62
+ process(:post, path, params, headers)
63
+ end
64
+
65
+ # ### Slice::Client#patch(path, params = nil, headers = nil)
66
+ # Sends PATCH request with given parameters, then returns a Slice::Response.
67
+ # `params` are JSON-encoded and used as request body.
68
+ #
69
+ # ```rb
70
+ # client.patch("/api/v1/items/123", title: "...", body: "...")
71
+ # ```
72
+ #
73
+ def patch(path, params = nil, headers = nil)
74
+ process(:patch, path, params, headers)
75
+ end
76
+
77
+ # ### Slice::Client#put(path, params = nil, headers = nil)
78
+ # Sends PUT request, then returns a Slice::Response.
79
+ # `params` are JSON-encoded and used as request body.
80
+ #
81
+ # ```rb
82
+ # client.put("/api/v1/items/123")
83
+ # ```
84
+ #
85
+ def put(path, params = nil, headers = nil)
86
+ process(:put, path, params, headers)
87
+ end
88
+
89
+ # ### Slice::Client#delete(path, params = nil, headers = nil)
90
+ # Sends DELETE request, then returns a Slice::Response.
91
+ # `params` are url-encoded and used as URI query string.
92
+ #
93
+ # ```rb
94
+ # client.delete("/api/v1/items/123")
95
+ # ```
96
+ #
97
+ def delete(path, params = nil, headers = nil)
98
+ process(:delete, path, params, headers)
99
+ end
100
+
101
+ # ### Slice::Client#connection
102
+ # Returns a Faraday::Connection to customize by your favorite middlewares.
103
+ #
104
+ # ```rb
105
+ # client.connection.response :logger
106
+ # ```
107
+ #
108
+ def connection
109
+ @connection ||= Faraday.new(faraday_client_options) do |connection|
110
+ connection.request :json
111
+ connection.response :json
112
+ connection.adapter Faraday.default_adapter
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def default_headers
119
+ headers = DEFAULT_HEADERS.clone
120
+ headers["Authorization"] = "Bearer #{@access_token}" if @access_token
121
+ headers
122
+ end
123
+
124
+ def faraday_client_options
125
+ {
126
+ headers: default_headers,
127
+ ssl: {
128
+ verify: @ssl,
129
+ },
130
+ url: url_prefix,
131
+ }
132
+ end
133
+
134
+ def host
135
+ @host || DEFAULT_HOST
136
+ end
137
+
138
+ def process(request_method, path, params, headers)
139
+ Slice::Response.new(
140
+ connection.send(
141
+ request_method,
142
+ URI.escape(path),
143
+ params,
144
+ headers,
145
+ )
146
+ )
147
+ end
148
+
149
+ def url_prefix
150
+ "https://#{host}"
151
+ end
152
+ end
153
+ end