magnum-pi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZmM2YTM5NDM4OTY5OTg1Y2I3N2RhYTEzN2MyMzUzZjg4NTVmNmE2Mg==
5
+ data.tar.gz: !binary |-
6
+ YzE4OGIxNzU5ZjAyYjk5ZTBlNGU3NGFkZGM3ZDlkMzJlYmY2YzVhNw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YjRjMzRlZjEyOTNiZjAyMDA3NzAxMDAzOTIxNWFiY2IwMjQzNDcwZTUwMjQw
10
+ ODRhMTVlY2UzODU4Yjc5MzhiMTI0NDIxYWVlN2I4MzlhNDBkNTVhZTVjZjJh
11
+ NGY4YzY2NGYxZjZiMmI3NjEzYzU2ZjQ5ZWU3NmExZWJkMWVlMzk=
12
+ data.tar.gz: !binary |-
13
+ OGIyZDcxNzMwYjlkNWEwMzk3MDQ1ODNjNTUyYjE1MDE2OWY4NTQ2MDFlMDU4
14
+ YTU1MzM5NDY1Nzk1M2Q3MWQyZjRmYWZiOGU2ZDhkZWY1YzRhZTA3ZGE3ODZi
15
+ NTQxNmEyNDliZmE4MjA3M2ZmMzkyNzdiNzkyNDMyZDRiMDdiY2I=
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ .DS_Store
2
+ .bundle
3
+ .rvmrc
4
+ Gemfile.lock
5
+ doc
6
+ pkg
7
+ test/coverage
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - 1.9.2
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,5 @@
1
+ = MagnumPI CHANGELOG
2
+
3
+ == Version 0.1.0 (March 26, 2014)
4
+
5
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem "magnum-pi", :path => "."
7
+ gem "pry"
8
+ end
9
+
10
+ group :test do
11
+ gem "simplecov", :require => false
12
+ gem "minitest"
13
+ gem "mocha"
14
+ end
data/README.rdoc ADDED
@@ -0,0 +1,31 @@
1
+ == MagnumPI {<img src="https://secure.travis-ci.org/archan937/magnum-pi.png"/>}[http://travis-ci.org/archan937/magnum-pi] {<img src="https://codeclimate.com/github/archan937/magnum-pi.png"/>}[https://codeclimate.com/github/archan937/magnum-pi]
2
+
3
+ Create an easy interface to talk with APIs
4
+
5
+ === Installation
6
+
7
+ ==== Using Bundler
8
+
9
+ Add <tt>MagnumPI</tt> in <tt>Gemfile</tt> as a gem dependency:
10
+
11
+ gem "magnum-pi"
12
+
13
+ Run the following in your console to install with Bundler:
14
+
15
+ $ bundle install
16
+
17
+ === TODO
18
+
19
+ * Support OAuth using APIs
20
+
21
+ === License
22
+
23
+ Copyright (c) 2014 Paul Engel, released under the MIT license
24
+
25
+ http://gettopup.com – http://github.com/archan937 – http://twitter.com/archan937 – {pm_engel@icloud.com}[mailto:pm_engel@icloud.com]
26
+
27
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
28
+
29
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
30
+
31
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ task :default => :test
7
+
8
+ Rake::TestTask.new do |test|
9
+ test.pattern = "test/**/test_*.rb"
10
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/examples/vimeo.rb ADDED
@@ -0,0 +1,43 @@
1
+ require "bundler"
2
+ Bundler.require :default, :development
3
+
4
+ #
5
+ # Usage:
6
+ #
7
+ # Vimeo.get "archan937/info"
8
+ # Vimeo.user_info "archan937"
9
+ # Vimeo.user_info :user => "archan937"
10
+ #
11
+ # Vimeo.download "archan937.json", :get, "archan937/info"
12
+ # Vimeo.user_info ["archan937"], "archan937.json"
13
+ # Vimeo.user_info({:user => "archan937"}, "archan937.json")
14
+ #
15
+ # Vimeo.get "channel/ruby/videos"
16
+ # Vimeo.channel_videos "ruby"
17
+ # Vimeo.channel_videos ["ruby"], "ruby.json"
18
+ #
19
+
20
+ module Vimeo
21
+ extend MagnumPI
22
+
23
+ api do
24
+ uri "http://vimeo.com/api/v2"
25
+ format :json
26
+ end
27
+
28
+ resources do
29
+ user_info :get, var(:user), "info"
30
+ channel_videos :get, "channel", var(:channel), "videos"
31
+ end
32
+
33
+ private
34
+
35
+ def self.to_url(*args)
36
+ "#{super}/#{args.join("/")}.#{api[:format]}"
37
+ end
38
+
39
+ def self.to_params(url, *args)
40
+ args[0].is_a?(Hash) ? args[0].slice(:page) : {}
41
+ end
42
+
43
+ end
data/lib/magnum-pi.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "mechanize"
2
+ require "oj"
3
+ require "xmlsimple"
4
+
5
+ require "magnum-pi/gem_ext"
6
+ require "magnum-pi/dsl"
7
+ require "magnum-pi/api"
8
+ require "magnum-pi/version"
9
+
10
+ module MagnumPI
11
+ def self.extended(base)
12
+ base.extend API
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ require "magnum-pi/api/scheme"
2
+ require "magnum-pi/api/resources"
3
+ require "magnum-pi/api/instance"
4
+ require "magnum-pi/api/consumer"
5
+
6
+ module MagnumPI
7
+ module API
8
+
9
+ def self.extended(base)
10
+ if base.is_a? Class
11
+ base.send :include, Instance
12
+ base.send :include, Consumer
13
+ else
14
+ base.extend Consumer
15
+ end
16
+ end
17
+
18
+ def api(&block)
19
+ @api ||= Scheme.new
20
+ if block_given?
21
+ @api.instance_eval &block
22
+ else
23
+ @api
24
+ end
25
+ end
26
+
27
+ def resources(&block)
28
+ @resources ||= Resources.new
29
+ if block_given?
30
+ @resources.instance_eval &block
31
+ else
32
+ @resources
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,92 @@
1
+ module MagnumPI
2
+ module API
3
+ module Consumer
4
+ class Error < StandardError; end
5
+
6
+ def get(*args)
7
+ url, params = parse_args *args
8
+ parse_content request(:get, url, params).content
9
+ end
10
+
11
+ def post(*args)
12
+ url, params = parse_args *args
13
+ parse_content request(:post, url, params).content
14
+ end
15
+
16
+ def download(target, method, *args)
17
+ url, params = parse_args *args
18
+ File.delete target if File.exists? target
19
+ request(method, url, params).save_as target
20
+ true
21
+ end
22
+
23
+ def resource(name, variables = {}, save_as = nil)
24
+ args = parse_resource_variables(resources[name], variables)
25
+ args = [:download, save_as].concat args if save_as
26
+ send *args
27
+ end
28
+
29
+ private
30
+
31
+ def method_missing(name, *args)
32
+ resources[name.to_sym] ? resource(name, *args) : super
33
+ end
34
+
35
+ def request(method, url, params)
36
+ agent.send method, url, params
37
+ rescue Mechanize::ResponseCodeError => e
38
+ raise Error, e.message, e.backtrace
39
+ end
40
+
41
+ def agent
42
+ @agent ||= begin
43
+ Mechanize.new.tap do |agent|
44
+ agent.verify_mode = OpenSSL::SSL::VERIFY_NONE
45
+ agent.pluggable_parser.default = Mechanize::Download
46
+ end
47
+ end
48
+ end
49
+
50
+ def parse_args(*args)
51
+ url = to_url(*args)
52
+ [url, to_params(url, *args)]
53
+ end
54
+
55
+ def parse_resource_variables(resource, variables)
56
+ variables = normalize_resource_variables resource, variables
57
+ resource.collect do |arg|
58
+ arg.is_a?(Resources::Variable) ? (variables[arg.name.to_s] || variables[arg.name.to_sym]) : arg
59
+ end
60
+ end
61
+
62
+ def normalize_resource_variables(resource, variables)
63
+ if !variables.is_a?(Hash) && (vars = resource.select{|x| x.is_a?(Resources::Variable)}).any?
64
+ variables = [variables].flatten
65
+ raise ArgumentError, "Unexpected amount of variables: #{variables.size} (expected: #{vars.size})" unless variables.size == vars.size
66
+ variables = Hash[vars.collect(&:name).zip(variables)]
67
+ end
68
+ variables
69
+ end
70
+
71
+ def to_url(*args)
72
+ api[:uri]
73
+ end
74
+
75
+ def to_params(url, *args)
76
+ raise NotImplementedError
77
+ end
78
+
79
+ def parse_content(response)
80
+ case api[:format].to_s
81
+ when "json"
82
+ Oj.load response
83
+ when "xml"
84
+ XmlSimple.xml_in response
85
+ else
86
+ response
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,23 @@
1
+ module MagnumPI
2
+ module API
3
+ module Instance
4
+
5
+ def initialize(params = {})
6
+ super()
7
+ @api = self.class.api.finalize params
8
+ @resources = self.class.resources.to_hash
9
+ end
10
+
11
+ private
12
+
13
+ def api
14
+ @api
15
+ end
16
+
17
+ def resources
18
+ @resources
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ module MagnumPI
2
+ module API
3
+ class Resources < DSL
4
+
5
+ class Variable
6
+ attr_accessor :name
7
+ end
8
+
9
+ def var(name)
10
+ Variable.new.tap do |variable|
11
+ variable.name = name
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,47 @@
1
+ module MagnumPI
2
+ module API
3
+ class Scheme < DSL
4
+
5
+ def initialize
6
+ super
7
+ uri ::String
8
+ format ::Symbol
9
+ end
10
+
11
+ def finalize(params = {})
12
+ @types = (types = _types).dup
13
+ @values = (values = _values).dup
14
+ params.each do |name, value|
15
+ process_value name, [value], nil
16
+ end
17
+ to_hash
18
+ ensure
19
+ @types = types
20
+ @values = values
21
+ end
22
+
23
+ private
24
+
25
+ def _types
26
+ @types ||= {}
27
+ end
28
+
29
+ def process_value(name, args, block)
30
+ is_a_class = (value = args[0]).class == ::Class
31
+ set_type name, is_a_class ? value : value.class
32
+ set_value name, value unless is_a_class
33
+ end
34
+
35
+ def set_type(name, type)
36
+ _types[name] ||= type
37
+ end
38
+
39
+ def value_error_message(name, value)
40
+ unless value.is_a?(type = _types[name])
41
+ "expected #{type}"
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,62 @@
1
+ module MagnumPI
2
+ class DSL < BasicObject
3
+
4
+ def initialize(*valid_keys, &block)
5
+ @valid_keys = valid_keys.collect &:to_sym
6
+ instance_eval &block if ::Kernel.block_given?
7
+ end
8
+
9
+ def class
10
+ (class << self; self end).superclass
11
+ end
12
+
13
+ def [](name)
14
+ _values[name]
15
+ end
16
+
17
+ def slice(*keys)
18
+ _values.slice *keys
19
+ end
20
+
21
+ def inspect
22
+ _values.inspect
23
+ end
24
+
25
+ def to_hash
26
+ _values.to_hash
27
+ end
28
+
29
+ def to_s
30
+ _values.to_s
31
+ end
32
+
33
+ private
34
+
35
+ def _values
36
+ @values ||= {}
37
+ end
38
+
39
+ def method_missing(name, *args, &block)
40
+ process_value name, args, block
41
+ end
42
+
43
+ def process_value(name, value, block)
44
+ set_value name, value
45
+ end
46
+
47
+ def set_value(name, value)
48
+ unless @valid_keys.empty? || @valid_keys.include?(name)
49
+ ::Kernel.raise ::ArgumentError, "Invalid key: '#{name}' (valid: #{@valid_keys.inspect})"
50
+ end
51
+ if error_message = value_error_message(name, value)
52
+ ::Kernel.raise ::ArgumentError, "Invalid value for '#{name}': #{value.inspect} (#{error_message})"
53
+ end
54
+ _values[name] = value
55
+ end
56
+
57
+ def value_error_message(name, value)
58
+ # override this method
59
+ end
60
+
61
+ end
62
+ end