plz 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 488ff35d58b0afabb4dc2ef94aafee3456bec27f
4
+ data.tar.gz: db861eecffcf54f36e841e3472ba135522e42190
5
+ SHA512:
6
+ metadata.gz: ae44fcd683b3a0abb5df567df603cc4384ae3ce83adcdd7c0df2fc6d2b83859b226bebbba18dce34e48214806bafa4e53b7578c74e161cd4e47e6bfa0060b8de
7
+ data.tar.gz: 9453b228fc5806abb8d50a666aed30f92cd84b97c5436fcd5b8a4e63bea9455f09c66e43d00314bb029c8a1eae53077de2acf7a3fffd4ffd28614673f6f936b7
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in plz.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Ryo Nakamura
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.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Plz
2
+ JSON Schema based command line HTTP client.
3
+
4
+ ## Usage
5
+
6
+ ### Install
7
+ ```sh
8
+ $ gem install plz
9
+ ```
10
+
11
+ ### Synopsis
12
+ ```sh
13
+ $ plz <action> <target> [headers|params]
14
+ | | | |
15
+ | | | `---- key=value ({"key":"value"}) or key:=value ({"key":value})
16
+ | | | params can be:
17
+ | | | * URI Template variable
18
+ | | | * Query string in GET method
19
+ | | | * Request body in other methods
20
+ | | |
21
+ | | `----------- Key:value
22
+ | |
23
+ | `--------------------- target resource name (e.g. user, recipe, etc.)
24
+ |
25
+ `------------------------------ action name (e.g. show, list, create, delete, etc.)
26
+ ```
27
+
28
+ ### Schema
29
+ To use Plz, you need to have a JSON Schema file at `./schema.json` or `./schema.yaml`,
30
+ that describes about the API where you want to send HTTP request.
31
+ Plz interprets command-line arguments based on that JSON Schema, then sends HTTP request.
32
+
33
+ ### Example
34
+ ```sh
35
+ # GET /users
36
+ $ plz list user
37
+ [
38
+ {
39
+ "id": 1,
40
+ "name": "alice"
41
+ },
42
+ {
43
+ "id": 2,
44
+ "name": "bob"
45
+ }
46
+ ]
47
+
48
+ # GET /users/2
49
+ $ plz show user id=2
50
+ {
51
+ "id": 2,
52
+ "name": "bob"
53
+ }
54
+
55
+ # POST /users with {"name":"charlie"} params
56
+ $ plz create user name=charlie
57
+ {
58
+ "id": 3,
59
+ "name": "charlie"
60
+ }
61
+
62
+ # POST /users with {"name":"dave",age:20} params
63
+ $ plz create user name=dave age:=20
64
+ {
65
+ "id": 4,
66
+ "age":20
67
+ "name": "dave"
68
+ }
69
+
70
+ # POST /users with Api-Access-Token:123 header and {"name":"ellen"} params
71
+ $ plz create user name=ellen Api-Access-Token:123
72
+ {
73
+ "id": 5,
74
+ "name": "ellen"
75
+ }
76
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/plz ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
3
+ require "plz"
4
+
5
+ command = Plz::CommandBuilder.call(ARGV)
6
+ command.call
data/lib/plz.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "active_support/core_ext/string/inflections"
2
+ require "active_support/core_ext/string/strip"
3
+ require "faraday"
4
+ require "faraday_middleware"
5
+ require "json"
6
+ require "json_schema"
7
+ require "pathname"
8
+ require "yaml"
9
+
10
+ require "plz/error"
11
+ require "plz/command"
12
+ require "plz/command_builder"
13
+ require "plz/error_command"
14
+ require "plz/version"
@@ -0,0 +1,71 @@
1
+ module Plz
2
+ class Command
3
+ # @param action_name [String]
4
+ # @param target_name [String]
5
+ # @param headers [Hash]
6
+ # @param params [Hash]
7
+ # @param schema [Hash]
8
+ def initialize(action_name: nil, target_name: nil, headers: nil, params: nil, schema: nil)
9
+ @action_name = action_name
10
+ @target_name = target_name
11
+ @headers = headers
12
+ @params = params
13
+ @schema = schema
14
+ end
15
+
16
+ # TODO
17
+ # Sends an HTTP request and logs out the response
18
+ def call
19
+ puts client.send(method, path, @params, @headers).body
20
+ end
21
+
22
+ private
23
+
24
+ # @return [String]
25
+ def path
26
+ current_link.href
27
+ end
28
+
29
+ # @return [Symbol]
30
+ def method
31
+ current_link.method
32
+ end
33
+
34
+ # @return [JsonSchema::Schema::Link, nil]
35
+ def current_link
36
+ @current_link ||= json_schema.properties.find do |key, schema|
37
+ if key == @target_name
38
+ schema.links.find do |link|
39
+ if link.href && link.method && link.title.underscore == @action_name
40
+ return link
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ # @return JsonSchema::Schema
48
+ # @raise [JsonSchema::SchemaError]
49
+ def json_schema
50
+ @json_schema ||= JsonSchema.parse!(@schema).tap(&:expand_references!)
51
+ end
52
+
53
+ # @return [Faraday::Connection]
54
+ def client
55
+ Faraday.new(url: base_url) do |connection|
56
+ connection.request :json
57
+ connection.adapter :net_http
58
+ end
59
+ end
60
+
61
+ # Extracts the base url of the API
62
+ # @return [String, nil]
63
+ def base_url
64
+ json_schema.links.find do |link|
65
+ if link.href && link.rel == "self"
66
+ return link.href
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,158 @@
1
+ module Plz
2
+ class CommandBuilder
3
+ SCHEMA_FILE_PATH_PATTERN = "{.,config}/schema.{json,yml}"
4
+
5
+ # Builds callable command object from given ARGV
6
+ # @return [Plz::Command]
7
+ # @example
8
+ # Plz::CommandBuilder.call(ARGV).call
9
+ def self.call(arguments)
10
+ new(arguments).call
11
+ end
12
+
13
+ # @param [Array<String>] ARGV
14
+ def initialize(arguments)
15
+ @arguments = arguments
16
+ end
17
+
18
+ # @return [Plz::Command] Callable command object
19
+ def call
20
+ validate!
21
+ Command.new(
22
+ action_name: action_name,
23
+ target_name: target_name,
24
+ headers: headers,
25
+ params: params,
26
+ schema: schema,
27
+ )
28
+ rescue Error => error
29
+ ErrorCommand.new(error)
30
+ end
31
+
32
+ private
33
+
34
+ # @raise [Plz::Error] Raises if invalid arguments given
35
+ def validate!
36
+ case
37
+ when !has_action_name?
38
+ raise NoActionName
39
+ when !has_target_name?
40
+ raise NoTargetName
41
+ when !has_schema_file?
42
+ raise SchemaFileNotFound
43
+ when !has_valid_schema_file?
44
+ raise InvalidSchemaFile, schema_file_pathname
45
+ end
46
+ end
47
+
48
+ # @return [true, false] True if given arguments include action name
49
+ def has_action_name?
50
+ !!action_name
51
+ end
52
+
53
+ # @return [true, false] True if given arguments include target name
54
+ def has_target_name?
55
+ !!target_name
56
+ end
57
+
58
+ # @return [true, false] True if schema file exists
59
+ def has_schema_file?
60
+ !!schema_file_pathname
61
+ end
62
+
63
+ # @return [true, false] True if no error occured in parsing schema file
64
+ def has_valid_schema_file?
65
+ !!schema
66
+ end
67
+
68
+ # @return [Hash]
69
+ def schema
70
+ @schema ||= begin
71
+ case schema_file_pathname.extname
72
+ when ".yml"
73
+ YAML.load(schema_file_body)
74
+ else
75
+ JSON.parse(schema_file_body)
76
+ end
77
+ end
78
+ rescue
79
+ end
80
+
81
+ # @return [String]
82
+ def schema_file_body
83
+ @schema_file_body ||= schema_file_pathname.read
84
+ end
85
+
86
+ # @return [Pathname, nil] Found schema file path
87
+ def schema_file_pathname
88
+ @schema_file_pathname ||= Pathname.glob(SCHEMA_FILE_PATH_PATTERN).first
89
+ end
90
+
91
+ # @return [String, nil] Given action name
92
+ def action_name
93
+ ARGV[0]
94
+ end
95
+
96
+ # @return [String, nil] Given target name
97
+ def target_name
98
+ ARGV[1]
99
+ end
100
+
101
+ # TODO
102
+ # @return [Hash] Params made from given arguments
103
+ def params
104
+ {}
105
+ end
106
+
107
+ # TODO
108
+ # @return [Hash] Headers made from given arguments
109
+ def headers
110
+ end
111
+
112
+ class Error < Error
113
+ USAGE = <<-EOS.strip_heredoc
114
+ $ plz <action> <target> [headers|params]
115
+ | | | |
116
+ | | | `---- key=value ({"key":"value"}) or key:=value ({"key":value})
117
+ | | | params can be:
118
+ | | | * URI Template variable
119
+ | | | * Query string in GET method
120
+ | | | * Request body in other methods
121
+ | | |
122
+ | | `----------- Key:value
123
+ | |
124
+ | `--------------------- target resource name (e.g. user, recipe, etc.)
125
+ |
126
+ `------------------------------ action name (e.g. show, list, create, delete, etc.)
127
+ EOS
128
+ end
129
+
130
+ class NoActionName < Error
131
+ def to_s
132
+ "You didn't pass action name\n#{USAGE}"
133
+ end
134
+ end
135
+
136
+ class NoTargetName < Error
137
+ def to_s
138
+ "You didn't pass target name\n#{USAGE}"
139
+ end
140
+ end
141
+
142
+ class SchemaFileNotFound < Error
143
+ def to_s
144
+ "Schema file was not found in #{SCHEMA_FILE_PATH_PATTERN}"
145
+ end
146
+ end
147
+
148
+ class InvalidSchemaFile < Error
149
+ def initialize(pathname)
150
+ @pathname = pathname
151
+ end
152
+
153
+ def to_s
154
+ "Failed to parse #{@pathname}"
155
+ end
156
+ end
157
+ end
158
+ end
data/lib/plz/error.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Plz
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ module Plz
2
+ class ErrorCommand
3
+ # @param error [Plz::Error] Error to show error message to user
4
+ def initialize(error)
5
+ @error = error
6
+ end
7
+
8
+ # Logs out error reason and usage, then exits with error code 1
9
+ def call
10
+ puts "Error: #{@error}"
11
+ exit(1)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Plz
2
+ VERSION = "0.0.1"
3
+ end
data/plz.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "plz/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "plz"
7
+ spec.version = Plz::VERSION
8
+ spec.authors = ["Ryo Nakamura"]
9
+ spec.email = ["r7kamura@gmail.com"]
10
+ spec.summary = "JSON Schema based command line HTTP client."
11
+ spec.homepage = "https://github.com/r7kamura/plz"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_dependency "activesupport"
20
+ spec.add_dependency "faraday"
21
+ spec.add_dependency "faraday_middleware"
22
+ spec.add_dependency "json_schema"
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ end
data/schema.yml ADDED
@@ -0,0 +1,81 @@
1
+ ---
2
+ "$schema": http://json-schema.org/draft-04/hyper-schema
3
+ definitions:
4
+ user:
5
+ title: User
6
+ description: Each user who is managed by us
7
+ type:
8
+ - object
9
+ required:
10
+ - id
11
+ definitions:
12
+ id:
13
+ description: Auto incremental unique ID
14
+ example: 1
15
+ readOnly: true
16
+ type:
17
+ - integer
18
+ name:
19
+ description: Human readable user name
20
+ example: alice
21
+ type:
22
+ - string
23
+ home:
24
+ description: True if the user exists in the location
25
+ example: true
26
+ type:
27
+ - boolean
28
+ email:
29
+ description: Email for fetching gravator icon
30
+ example: alice@example.com
31
+ type:
32
+ - string
33
+ updated_at:
34
+ description: When this resource is updated
35
+ example: "2014-06-10T21:05:20+09:00"
36
+ readOnly: true
37
+ format: date-time
38
+ type:
39
+ - string
40
+ links:
41
+ - description: List all users
42
+ href: "/users"
43
+ method: GET
44
+ rel: instances
45
+ title: List
46
+ - description: Create a new user
47
+ href: "/users"
48
+ method: POST
49
+ rel: create
50
+ title: Create
51
+ - description: Update the user
52
+ href: "/users/{(#/definitions/users/definitions/id)}"
53
+ method: PATCH
54
+ rel: update
55
+ title: Update
56
+ - description: Delete the user
57
+ href: "/users/{(#/definitions/users/definitions/id)}"
58
+ method: DELETE
59
+ rel: delete
60
+ title: Delete
61
+ properties:
62
+ id:
63
+ "$ref": "#/definitions/user/definitions/id"
64
+ name:
65
+ "$ref": "#/definitions/user/definitions/name"
66
+ home:
67
+ "$ref": "#/definitions/user/definitions/home"
68
+ email:
69
+ "$ref": "#/definitions/user/definitions/email"
70
+ updated_at:
71
+ "$ref": "#/definitions/user/definitions/updated_at"
72
+ properties:
73
+ user:
74
+ "$ref": "#/definitions/user"
75
+ type:
76
+ - object
77
+ description: API server for TQKey
78
+ links:
79
+ - href: http://localhost:8080
80
+ rel: self
81
+ title: Dummy API
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: plz
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryo Nakamura
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday_middleware
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
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: json_schema
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ - r7kamura@gmail.com
100
+ executables:
101
+ - plz
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - bin/plz
111
+ - lib/plz.rb
112
+ - lib/plz/command.rb
113
+ - lib/plz/command_builder.rb
114
+ - lib/plz/error.rb
115
+ - lib/plz/error_command.rb
116
+ - lib/plz/version.rb
117
+ - plz.gemspec
118
+ - schema.yml
119
+ homepage: https://github.com/r7kamura/plz
120
+ licenses:
121
+ - MIT
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.2.2
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: JSON Schema based command line HTTP client.
143
+ test_files: []
144
+ has_rdoc: