grifter 0.0.4

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