plz 0.0.1

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 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: