grifter 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source :rubygems
2
+
3
+ #gemspec
4
+
5
+ gem 'json'
6
+
7
+ group :development do
8
+ gem 'rspec'
9
+ gem 'pry'
10
+ gem 'awesome_print'
11
+ gem 'jeweler'
12
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Robert Schultheis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "grifter"
18
+ gem.homepage = "http://github.com/knewton/grifter"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Make calls to HTTP JSON APIs with ease and confidence}
21
+ gem.description = %Q{convention based approach to interfacing with an HTTP JSON API.}
22
+ gem.email = "rob@knewton.com"
23
+ gem.authors = ["Robert Schultheis"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core/rake_task'
29
+ RSpec::Core::RakeTask.new(:spec)
30
+
31
+ task :default => :spec
32
+
33
+ require 'rdoc/task'
34
+ Rake::RDocTask.new do |rdoc|
35
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
36
+
37
+ rdoc.rdoc_dir = 'rdoc'
38
+ rdoc.title = "grifter #{version}"
39
+ rdoc.rdoc_files.include('README*')
40
+ rdoc.rdoc_files.include('lib/**/*.rb')
41
+ end
@@ -0,0 +1,119 @@
1
+ Grifter
2
+ =======
3
+ Grifter makes it smooth to work with JSON HTTP APIs with confidence
4
+
5
+ Features
6
+ --------
7
+ - Work with multiple APIs
8
+ - Work with multiple deployment environments (Staging, Production, etc.)
9
+ - Script calls to API(s)
10
+ - Command line calls to API(s)
11
+ - Craft clean API tests using the included RSPec helper
12
+ - Unified approach to handling request errors
13
+ - Convention over configuration approach to defining the API interface
14
+
15
+ Getting Started
16
+ ---------------
17
+ Lets demo how this works using a simple example of an API that requires no
18
+ authentication.
19
+
20
+ The OpenWeatherMap is a good candidate for a simple API
21
+ which is accessible without needing any authentication key:
22
+ [http://api.openweathermap.org/]
23
+
24
+
25
+ ### make a project directory
26
+
27
+ mkdir weather
28
+ cd weather
29
+
30
+ ### setup grifter.yml
31
+
32
+ services:
33
+ owm:
34
+ hostname: api.openweathermap.org
35
+
36
+ ### make the grifts directory, and a grift file
37
+
38
+ mkdir owm_grifts
39
+ touch owm_grifts/weather_grifts.rb
40
+
41
+ ### add method for checking weather to owm/weather.rb
42
+ def weather_for city
43
+ owm.get "/data/2.5/weather?q=#{URI.encode(city)}"
44
+ end
45
+
46
+ ### Call it from the cmd line:
47
+ $ grift weather_for 'Pleasantville, NY'
48
+
49
+ And that returns something like this:
50
+ {"coord"=>{"lon"=>-73.79169, "lat"=>41.13436}, "sys"=>{"country"=>"United States of America", "sunrise"=>1366883974, "sunset"=>1366933583}, "weather"=>[{"id"=>501, "main"=>"Rain", "description"=>"moderate rain", "icon"=>"10d"}], "base"=>"global stations", "main"=>{"temp"=>290.46, "humidity"=>26, "pressure"=>1020, "temp_min"=>289.15, "temp_max"=>292.59}, "wind"=>{"speed"=>2.06, "gust"=>4.11, "deg"=>265}, "rain"=>{"1h"=>2.32}, "clouds"=>{"all"=>0}, "dt"=>1366926419, "id"=>5131757, "name"=>"Pleasantville", "cod"=>200}
51
+
52
+ Use the -v command line option and see the full request/response logged to StdOut
53
+
54
+ ### Script it
55
+ Make a file called temperatures.rb with this in it:
56
+
57
+ [
58
+ 'New York, NY',
59
+ 'Toronto, Canada',
60
+ 'Paris, France',
61
+ 'Tokyo, Japan',
62
+ 'Sydney, Australia',
63
+ ].each do |city|
64
+ weather = weather_for city
65
+ kelvin = weather['main']['temp']
66
+ celcius = (kelvin - 273.15).round
67
+ puts "#{city}: #{celcius} celcius"
68
+ end
69
+
70
+ And then run the grift script like so:
71
+
72
+ grift -f temperatures.rb
73
+
74
+ And get this nice output:
75
+
76
+ I: [04/25/13 17:59:22][grifter] - Running data script 'temperatures.rb'
77
+ New York, NY: 18 celcius
78
+ Toronto, Canada: 7 celcius
79
+ Paris, France: 18 celcius
80
+ Tokyo, Japan: 16 celcius
81
+ Sydney, Australia: 14 celcius
82
+
83
+ ### Test it
84
+ Using the included helper module, testing an api becomes easy. Lets setup a simple RSpec example. Step one is create the spec folder:
85
+
86
+ mkdir spec
87
+
88
+ Setup spec/spec_helper.rb with contents like:
89
+
90
+ require 'grifter/helpers'
91
+
92
+ RSpec.configure do |config|
93
+ config.include Grifter::Helpers
94
+ end
95
+
96
+ Setup spec/weather_spec.rb with contents like:
97
+
98
+ require 'spec_helper'
99
+ describe "getting weather reports" do
100
+ it "should know the weather for New York City" do
101
+ response = weather_for 'New York, NY'
102
+ response['main'].keys.should =~ ['temp', 'temp_min', 'temp_max', 'humidity', 'pressure']
103
+ end
104
+ end
105
+
106
+ Run it:
107
+
108
+ gem install rspec
109
+ rspec
110
+
111
+ And get back:
112
+
113
+ 1 example, 0 failures
114
+
115
+
116
+ Copyright
117
+ ---------
118
+ Copyright (c) 2013 Knewton. See LICENSE.txt for
119
+ further details.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ require_relative '../lib/grifter'
5
+
6
+ Log = Grifter::Log
7
+
8
+ Log.level = Logger::INFO
9
+
10
+ #Deal with the cmd line
11
+ def parse_cmd_line
12
+ options = {
13
+ files: [],
14
+ config_file: 'grifter.yml',
15
+ authenticate: true,
16
+ environment: nil,
17
+ }
18
+
19
+ optparse = OptionParser.new do |opts|
20
+ opts.banner = %Q|
21
+ Grifter HTTP JSON APIs Client
22
+ example, run a data script: bin/grifter -f script.rb
23
+ example, call a method: bin/grifter <grift method name>
24
+
25
+ |
26
+
27
+ opts.on("-f", "--script=FILENAME",
28
+ "specify a script file to run") { |file| options[:files] << file }
29
+
30
+ opts.on("-v", "--verbose",
31
+ "enable debug logging") { Log.level = Logger::DEBUG }
32
+
33
+ opts.on("-c", "--config=FILENAME",
34
+ "config filename") { |fn| options[:config_file] = fn }
35
+
36
+ opts.on('-e', '--environment=ENVIRONMENT',
37
+ "environment name") { |e| options[:environment] = e.to_sym }
38
+
39
+ opts.on("-d", "--no_authenticate",
40
+ "Do not authenticate") { options[:authenticate] = false }
41
+
42
+ end
43
+ optparse.parse!
44
+ options
45
+ end
46
+ options = parse_cmd_line
47
+
48
+ grifter = Grifter.new options
49
+
50
+ if not(ARGV.empty?)
51
+ method = ARGV.shift
52
+ response = grifter.send(method.to_sym, *ARGV)
53
+ puts response.inspect
54
+
55
+ elsif not(options[:files].empty?)
56
+ options[:files].each do |script_file|
57
+ grifter.run_script_file(script_file)
58
+ end
59
+
60
+ else
61
+ Kernel.abort "Nothing to do? use -f or give a method name on the cmd line"
62
+ end
@@ -0,0 +1,7 @@
1
+ #base configuration of services goes here
2
+ services:
3
+ owm:
4
+ hostname: 'api.openweathermap.org'
5
+
6
+ grift_globs:
7
+ - 'example/**/*_grifts.rb'
@@ -0,0 +1,3 @@
1
+ def weather_for city
2
+ owm.get "/data/2.5/weather?q=#{URI.encode(city)}"
3
+ end
@@ -0,0 +1,12 @@
1
+ [
2
+ 'New York, NY',
3
+ 'Toronto, Canada',
4
+ 'Paris, France',
5
+ 'Tokyo, Japan',
6
+ 'Sydney, Australia',
7
+ ].each do |city|
8
+ weather = weather_for city
9
+ kelvin = weather['main']['temp']
10
+ celcius = (kelvin - 273.15).round
11
+ puts "#{city}: #{celcius} celcius"
12
+ end
@@ -0,0 +1,80 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "grifter"
8
+ s.version = "0.0.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Robert Schultheis"]
12
+ s.date = "2013-05-09"
13
+ s.description = "convention based approach to interfacing with an HTTP JSON API."
14
+ s.email = "rob@knewton.com"
15
+ s.executables = ["grift"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE.txt"
18
+ ]
19
+ s.files = [
20
+ "Gemfile",
21
+ "LICENSE.txt",
22
+ "Rakefile",
23
+ "Readme.md",
24
+ "VERSION",
25
+ "bin/grift",
26
+ "example/grifter.yml",
27
+ "example/owm_grifts/weather_grifts.rb",
28
+ "example/temperatures.rb",
29
+ "grifter.gemspec",
30
+ "lib/grifter.rb",
31
+ "lib/grifter/blankslate.rb",
32
+ "lib/grifter/configuration.rb",
33
+ "lib/grifter/helpers.rb",
34
+ "lib/grifter/http_service.rb",
35
+ "lib/grifter/json_helpers.rb",
36
+ "lib/grifter/log.rb",
37
+ "spec/configuration_spec.rb",
38
+ "spec/grifter_spec.rb",
39
+ "spec/http_service_spec.rb",
40
+ "spec/json_helpers_spec.rb",
41
+ "spec/resources/example_config.yml",
42
+ "spec/resources/grifter.yml",
43
+ "spec/resources/syntax_error_grifts/eval_error_grifts.rb",
44
+ "spec/resources/twitter_grifts/oauth_grifts.rb",
45
+ "spec/resources/twitter_grifts/timeline_grifts.rb",
46
+ "spec/rspec_helper_spec.rb",
47
+ "spec/support/require_all_lib_files.rb",
48
+ "spec/support/spec_helper.rb"
49
+ ]
50
+ s.homepage = "http://github.com/knewton/grifter"
51
+ s.licenses = ["MIT"]
52
+ s.require_paths = ["lib"]
53
+ s.rubygems_version = "1.8.24"
54
+ s.summary = "Make calls to HTTP JSON APIs with ease and confidence"
55
+
56
+ if s.respond_to? :specification_version then
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
60
+ s.add_runtime_dependency(%q<json>, [">= 0"])
61
+ s.add_development_dependency(%q<rspec>, [">= 0"])
62
+ s.add_development_dependency(%q<pry>, [">= 0"])
63
+ s.add_development_dependency(%q<awesome_print>, [">= 0"])
64
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
65
+ else
66
+ s.add_dependency(%q<json>, [">= 0"])
67
+ s.add_dependency(%q<rspec>, [">= 0"])
68
+ s.add_dependency(%q<pry>, [">= 0"])
69
+ s.add_dependency(%q<awesome_print>, [">= 0"])
70
+ s.add_dependency(%q<jeweler>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<json>, [">= 0"])
74
+ s.add_dependency(%q<rspec>, [">= 0"])
75
+ s.add_dependency(%q<pry>, [">= 0"])
76
+ s.add_dependency(%q<awesome_print>, [">= 0"])
77
+ s.add_dependency(%q<jeweler>, [">= 0"])
78
+ end
79
+ end
80
+
@@ -0,0 +1,77 @@
1
+ require_relative 'grifter/http_service'
2
+ require_relative 'grifter/configuration'
3
+ require_relative 'grifter/log'
4
+ require_relative 'grifter/blankslate'
5
+
6
+ class Grifter
7
+ include Grifter::Configuration
8
+
9
+ DefaultConfigOptions = {
10
+ #TODO: service_config: nil,
11
+ grift_globs: ['*_grifts/**/*_grifts.rb'],
12
+ authenticate: false,
13
+ load_from_config_file: true,
14
+ services: {},
15
+ }
16
+ def initialize options={}
17
+ options = DefaultConfigOptions.merge(options)
18
+ @config = if options[:load_from_config_file]
19
+ options.merge load_config_file(options)
20
+ else
21
+ options
22
+ end
23
+
24
+ #setup the services
25
+ @services = []
26
+ @config[:services].each_pair do |service_name, service_config|
27
+ service = HTTPService.new(service_config)
28
+ define_singleton_method service_name.intern do
29
+ service
30
+ end
31
+ @services << service
32
+ end
33
+
34
+ #setup the grifter methods if any
35
+ if @config[:grift_globs]
36
+ @config[:grift_globs].each do |glob|
37
+ Dir[glob].each do |grifter_file|
38
+ load_grifter_file grifter_file
39
+ end
40
+ end
41
+ end
42
+
43
+ if @config[:authenticate]
44
+ self.grifter_authenticate_do
45
+ end
46
+ end
47
+
48
+ attr_reader :services
49
+
50
+ def load_grifter_file filename
51
+ Log.debug "Loading extension file '#{filename}'"
52
+ anon_mod = Module.new
53
+ #by evaling in a anonymous module, we protect this class's namespace
54
+ load_dir = File.dirname(filename)
55
+ $: << load_dir
56
+ anon_mod.class_eval(IO.read(filename), filename, 1)
57
+ $:.pop
58
+ self.extend anon_mod
59
+ end
60
+
61
+ def run_script_file filename
62
+ Log.info "Running data script '#{filename}'"
63
+ raise "No such file '#{filename}'" unless File.exist? filename
64
+ #by running in a anonymous class, we protect this class's namespace
65
+ anon_class = BlankSlate.new(self)
66
+ anon_class.instance_eval(IO.read(filename), filename, 1)
67
+ end
68
+
69
+ #calls all methods that end with grifter_authenticate
70
+ def grifter_authenticate_do
71
+ auth_methods = self.singleton_methods.select { |m| m =~ /grifter_authenticate$/ }
72
+ auth_methods.each do |m|
73
+ Log.debug "Executing a grifter_authentication on method: #{m}"
74
+ self.send(m)
75
+ end
76
+ end
77
+ end