hatt 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: 38589e6ed1df4b139b3339624ba5eb130548c062
4
+ data.tar.gz: 6b52ef37b1b0fc458b9ffd88c951e20d0efee1bc
5
+ SHA512:
6
+ metadata.gz: a69fbe934e0a246fc33c7e3de4c00f5ae52fff5af334a408dc86319f6c2213fec4ca3e9963993db03c5180d7f06eaaf4a58e500411bf3141a40e5288858d7abc
7
+ data.tar.gz: 8e88242846ac574f6f811b5166d307aee6f8234789c3aaa1b9058a8e1e14f3ede903f57c07c726eed1d2600b3ed099619f0f5abd0cea1c0dd4017cfc1f60c473
data/Gemfile ADDED
@@ -0,0 +1,27 @@
1
+ source :rubygems
2
+
3
+ # misc things from activesupport are used
4
+ # notifications are used to implement instrumentation
5
+ gem 'activesupport'
6
+ # faraday provides the basis for making http requests
7
+ gem 'faraday'
8
+ # when will json gem go into the standard lib anyways?
9
+ gem 'multi_json'
10
+ # tcfg provides the basis for configuration (hatt.yml) and environments (qa/production/etc)
11
+ gem 'tcfg', '~> 0.2.2'
12
+ # typhoes faraday adapter is the default for making http requests
13
+ # provides a useful mechanism for making concurrent requests as well
14
+ gem 'typhoeus'
15
+ # pry is the basis of the REPL feature of the hatt cmd line tool
16
+ gem 'pry'
17
+ # awesome_print makes pry better
18
+ gem 'awesome_print'
19
+
20
+ group :development do
21
+ gem 'debase'
22
+ gem 'jeweler'
23
+ gem 'rspec'
24
+ gem 'rubocop'
25
+ gem 'ruby-debug-ide'
26
+ gem 'simplecov'
27
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,138 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (5.1.0)
5
+ concurrent-ruby (~> 1.0, >= 1.0.2)
6
+ i18n (~> 0.7)
7
+ minitest (~> 5.1)
8
+ tzinfo (~> 1.1)
9
+ addressable (2.5.1)
10
+ public_suffix (~> 2.0, >= 2.0.2)
11
+ ast (2.3.0)
12
+ awesome_print (1.7.0)
13
+ builder (3.2.3)
14
+ coderay (1.1.1)
15
+ concurrent-ruby (1.0.5)
16
+ debase (0.2.1)
17
+ debase-ruby_core_source
18
+ debase-ruby_core_source (0.9.9)
19
+ descendants_tracker (0.0.4)
20
+ thread_safe (~> 0.3, >= 0.3.1)
21
+ diff-lcs (1.3)
22
+ docile (1.1.5)
23
+ ethon (0.10.1)
24
+ ffi (>= 1.3.0)
25
+ faraday (0.9.2)
26
+ multipart-post (>= 1.2, < 3)
27
+ ffi (1.9.18)
28
+ git (1.3.0)
29
+ github_api (0.11.3)
30
+ addressable (~> 2.3)
31
+ descendants_tracker (~> 0.0.1)
32
+ faraday (~> 0.8, < 0.10)
33
+ hashie (>= 1.2)
34
+ multi_json (>= 1.7.5, < 2.0)
35
+ nokogiri (~> 1.6.0)
36
+ oauth2
37
+ hashie (3.5.5)
38
+ highline (1.7.8)
39
+ i18n (0.8.1)
40
+ jeweler (2.3.5)
41
+ builder
42
+ bundler (>= 1.0)
43
+ git (>= 1.2.5)
44
+ github_api (~> 0.11.0)
45
+ highline (>= 1.6.15)
46
+ nokogiri (>= 1.5.10)
47
+ psych (~> 2.2)
48
+ rake
49
+ rdoc
50
+ semver2
51
+ json (2.1.0)
52
+ jwt (1.5.6)
53
+ method_source (0.8.2)
54
+ mini_portile2 (2.1.0)
55
+ minitest (5.10.1)
56
+ multi_json (1.12.1)
57
+ multi_xml (0.6.0)
58
+ multipart-post (2.0.0)
59
+ nokogiri (1.6.8.1)
60
+ mini_portile2 (~> 2.1.0)
61
+ oauth2 (1.3.1)
62
+ faraday (>= 0.8, < 0.12)
63
+ jwt (~> 1.0)
64
+ multi_json (~> 1.3)
65
+ multi_xml (~> 0.5)
66
+ rack (>= 1.2, < 3)
67
+ parser (2.4.0.0)
68
+ ast (~> 2.2)
69
+ powerpack (0.1.1)
70
+ pry (0.10.4)
71
+ coderay (~> 1.1.0)
72
+ method_source (~> 0.8.1)
73
+ slop (~> 3.4)
74
+ psych (2.2.4)
75
+ public_suffix (2.0.5)
76
+ rack (2.0.1)
77
+ rainbow (2.2.2)
78
+ rake
79
+ rake (12.0.0)
80
+ rdoc (5.1.0)
81
+ rspec (3.5.0)
82
+ rspec-core (~> 3.5.0)
83
+ rspec-expectations (~> 3.5.0)
84
+ rspec-mocks (~> 3.5.0)
85
+ rspec-core (3.5.4)
86
+ rspec-support (~> 3.5.0)
87
+ rspec-expectations (3.5.0)
88
+ diff-lcs (>= 1.2.0, < 2.0)
89
+ rspec-support (~> 3.5.0)
90
+ rspec-mocks (3.5.0)
91
+ diff-lcs (>= 1.2.0, < 2.0)
92
+ rspec-support (~> 3.5.0)
93
+ rspec-support (3.5.0)
94
+ rubocop (0.48.1)
95
+ parser (>= 2.3.3.1, < 3.0)
96
+ powerpack (~> 0.1)
97
+ rainbow (>= 1.99.1, < 3.0)
98
+ ruby-progressbar (~> 1.7)
99
+ unicode-display_width (~> 1.0, >= 1.0.1)
100
+ ruby-debug-ide (0.6.0)
101
+ rake (>= 0.8.1)
102
+ ruby-progressbar (1.8.1)
103
+ semver2 (3.4.2)
104
+ simplecov (0.14.1)
105
+ docile (~> 1.1.0)
106
+ json (>= 1.8, < 3)
107
+ simplecov-html (~> 0.10.0)
108
+ simplecov-html (0.10.0)
109
+ slop (3.6.0)
110
+ tcfg (0.2.2)
111
+ activesupport
112
+ thread_safe (0.3.6)
113
+ typhoeus (1.1.2)
114
+ ethon (>= 0.9.0)
115
+ tzinfo (1.2.3)
116
+ thread_safe (~> 0.1)
117
+ unicode-display_width (1.2.1)
118
+
119
+ PLATFORMS
120
+ ruby
121
+
122
+ DEPENDENCIES
123
+ activesupport
124
+ awesome_print
125
+ debase
126
+ faraday
127
+ jeweler
128
+ multi_json
129
+ pry
130
+ rspec
131
+ rubocop
132
+ ruby-debug-ide
133
+ simplecov
134
+ tcfg (~> 0.2.2)
135
+ typhoeus
136
+
137
+ BUNDLED WITH
138
+ 1.13.6
data/LICENSE.txt ADDED
@@ -0,0 +1,18 @@
1
+ Permission is hereby granted, free of charge, to any person obtaining
2
+ a copy of this software and associated documentation files (the
3
+ "Software"), to deal in the Software without restriction, including
4
+ without limitation the rights to use, copy, modify, merge, publish,
5
+ distribute, sublicense, and/or sell copies of the Software, and to
6
+ permit persons to whom the Software is furnished to do so, subject to
7
+ the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be
10
+ included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,120 @@
1
+ Hatt
2
+ =======
3
+ Do cool stuff with HTTP JSON APIs. Designed for the real world of developing systems based on service-oriented-architecture.
4
+
5
+ What is Hatt?
6
+ ----------------
7
+ Hatt is primarily designed to be used by software teams that build HTTP JSON services.
8
+ Hatt makes it easy to:
9
+ * Define "macro" methods that accomplish high level goals through service calls.
10
+ * Call services or macro methods from the command line, adhoc scripts, or programtically within any Ruby program.
11
+ * Test services using RSpec or other testing frameworks
12
+ * "Point" at different environments (eg. QA, Staging, Production)
13
+
14
+ Hatt relies heavily on the 'convention over configuration' approach. For very little code, you
15
+ get a lot of functionality.
16
+
17
+ Hatt is based on [Faraday](https://github.com/lostisland/faraday), thus there is basic support for making requests concurrently, and for swapping out the HTTP "adapter".
18
+
19
+ Getting Started
20
+ ---------------
21
+ Lets demo how this works using a simple example of an API that requires no
22
+ authentication.
23
+
24
+ The OpenWeatherMap is a good candidate for a simple API
25
+ which is accessible without needing any authentication key:
26
+ [http://api.openweathermap.org/]
27
+
28
+
29
+ ### make a project directory
30
+
31
+ mkdir weather
32
+ cd weather
33
+
34
+ ### setup hatt.yml
35
+
36
+ services:
37
+ owm:
38
+ hostname: api.openweathermap.org
39
+
40
+ ### make the hatts directory, and a hatt file
41
+
42
+ mkdir owm_hatts
43
+ touch owm_hatts/weather_hatts.rb
44
+
45
+ ### add method for checking weather to owm_hatts/weather.rb
46
+ def weather_for city
47
+ owm.get "/data/2.5/weather?q=#{URI.encode(city)}"
48
+ end
49
+
50
+ ### Call it from the cmd line:
51
+ $ hatt weather_for 'Pleasantville, NY'
52
+
53
+ And that returns something like this:
54
+ {"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}
55
+
56
+ Use the -v command line option and see the full request/response logged to StdOut
57
+
58
+ ### Script it
59
+ Make a file called temperatures.rb with this in it:
60
+
61
+ [
62
+ 'New York, NY',
63
+ 'Toronto, Canada',
64
+ 'Paris, France',
65
+ 'Tokyo, Japan',
66
+ 'Sydney, Australia',
67
+ ].each do |city|
68
+ weather = weather_for city
69
+ kelvin = weather['main']['temp']
70
+ celcius = (kelvin - 273.15).round
71
+ puts "#{city}: #{celcius} celcius"
72
+ end
73
+
74
+ And then run the hatt script like so:
75
+
76
+ hatt -f temperatures.rb
77
+
78
+ And get this nice output:
79
+
80
+ I: [04/25/13 17:59:22][hatt] - Running data script 'temperatures.rb'
81
+ New York, NY: 18 celcius
82
+ Toronto, Canada: 7 celcius
83
+ Paris, France: 18 celcius
84
+ Tokyo, Japan: 16 celcius
85
+ Sydney, Australia: 14 celcius
86
+
87
+ ### Test it
88
+ Using the included helper module, testing an api becomes easy. Lets setup a simple RSpec example. Step one is create the spec folder:
89
+
90
+ mkdir spec
91
+
92
+ Setup spec/spec_helper.rb with contents like:
93
+
94
+ require 'hatt/helpers'
95
+
96
+ RSpec.configure do |config|
97
+ config.include Hatt::Helpers
98
+ end
99
+
100
+ Setup spec/weather_spec.rb with contents like:
101
+
102
+ require 'spec_helper'
103
+ describe "getting weather reports" do
104
+ it "should know the weather for New York City" do
105
+ response = weather_for 'New York, NY'
106
+ expected_items = ['temp', 'temp_min', 'temp_max', 'humidity', 'pressure']
107
+ response['main'].keys.should include(*expected_items)
108
+ end
109
+ end
110
+
111
+ Run it:
112
+
113
+ gem install rspec
114
+ rspec
115
+
116
+ And get back:
117
+
118
+ 1 example, 0 failures
119
+
120
+
data/bin/hatt ADDED
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ require_relative '../lib/hatt'
5
+
6
+ Log = Hatt::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: 'hatt.yml',
15
+ authenticate: true,
16
+ repl: false,
17
+ # by leaving environment unset, hatt will use HATT_ENVIRONMENT variable if no -e is used on cmd line
18
+ # environment: nil,
19
+ }
20
+
21
+ optparse = OptionParser.new do |opts|
22
+ opts.banner = %(
23
+ HATT HTTP API Test Tool command line utility:
24
+ example, run a data script: bin/hatt -f script.rb
25
+ example, call a dsl method: bin/hatt <hatt dsl method name>
26
+
27
+ )
28
+
29
+ opts.on('-f', '--script=FILENAME',
30
+ 'specify a script file to run') { |file| options[:files] << file }
31
+
32
+ opts.on('-d', '--script-dir=dir',
33
+ 'specify a directory of hatt scripts, run all of them') { |dir| options[:files] += Dir["#{dir}/**/*.rb"] }
34
+
35
+ opts.on('-v', '--verbose',
36
+ 'debug logging, see every request and response in detail') { Log.level = Logger::DEBUG }
37
+
38
+ opts.on('-q', '--quiet',
39
+ 'quiet logging, warnings and errors only') { Log.level = Logger::WARN }
40
+
41
+ opts.on('-c', '--config=FILENAME',
42
+ 'config filename') { |fn| options[:config_file] = fn }
43
+
44
+ opts.on('-e', '--environment=ENVIRONMENT',
45
+ 'environment name') do |e|
46
+ # a bit unfortunate this has to be passed by env var, but it works
47
+ ENV['HATT_ENVIRONMENT'] = e
48
+ end
49
+
50
+ opts.on('-n', '--no-authenticate',
51
+ 'Do not authenticate') { options[:authenticate] = false }
52
+
53
+ opts.on('-l', '--list', 'Print each available hatt dsl method') do
54
+ options[:list_hatt_methods] = true
55
+ options[:authenticate] = false # no point in authenticating for --list
56
+ end
57
+
58
+ opts.on('-r', '--pry-repl', 'Launch an interactice repl with full access to hatt services and dsl') do
59
+ options[:repl] = true
60
+ end
61
+ end
62
+ optparse.parse!
63
+ options
64
+ end
65
+ options = parse_cmd_line
66
+
67
+ begin
68
+ hatt = Hatt.new options
69
+ rescue TCFG::NoSuchConfigFileError => e
70
+ Log.error e.message
71
+ Log.error <<-MSG
72
+ \n
73
+ Either use -c to specify the location of your hatt config file,
74
+ or create a file called hatt.yml in the current directory.
75
+
76
+ Review documentation on configuration here: <TODO>
77
+ MSG
78
+ Kernel.abort
79
+ end
80
+
81
+ if options[:list_hatt_methods]
82
+ puts 'HATT method listing'
83
+
84
+ hatt.singleton_methods.sort.each do |meth|
85
+ puts " - #{meth}(#{hatt.method(meth).parameters.join(', ')})"
86
+ end
87
+
88
+ exit
89
+ end
90
+
91
+ if !ARGV.empty?
92
+ # a hatt method has been specified on the command line
93
+ method = ARGV.shift
94
+ response = hatt.send(method.to_sym, *ARGV)
95
+ Log.debug "HATT method '#{method}' returned:\n" + response.inspect
96
+ puts response
97
+
98
+ elsif !options[:files].empty?
99
+ # some hatt files were specified on the command line
100
+ options[:files].each do |script_file|
101
+ response = hatt.run_script_file(script_file)
102
+ Log.debug "HATT script '#{script_file}' returtned: #{response.inspect}"
103
+ puts response
104
+ end
105
+
106
+ elsif options[:repl]
107
+ Log.debug 'Launching PRY REPL since --pry-repl was specified....'
108
+ hatt.launch_pry_repl
109
+ else
110
+ Kernel.abort 'Nothing to do? use -f or give a method name on the cmd line'
111
+ end
data/hatt.gemspec ADDED
@@ -0,0 +1,94 @@
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
+ # stub: hatt 0.0.1 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "hatt"
9
+ s.version = "0.0.1"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Robert Schultheis"]
14
+ s.date = "2017-05-12"
15
+ s.description = "convention based approach to interfacing with an HTTP JSON API."
16
+ s.email = "robert.schultheis@gmail.com"
17
+ s.executables = ["hatt"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE.txt",
20
+ "README.rdoc"
21
+ ]
22
+ s.files = [
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "bin/hatt",
27
+ "hatt.gemspec",
28
+ "lib/hatt.rb",
29
+ "lib/hatt/api_clients.rb",
30
+ "lib/hatt/base.rb",
31
+ "lib/hatt/blankslateproxy.rb",
32
+ "lib/hatt/configuration.rb",
33
+ "lib/hatt/dsl.rb",
34
+ "lib/hatt/hattmixin.rb",
35
+ "lib/hatt/http.rb",
36
+ "lib/hatt/json_helpers.rb",
37
+ "lib/hatt/log.rb",
38
+ "lib/hatt/mixin.rb",
39
+ "lib/hatt/singleton_mixin.rb"
40
+ ]
41
+ s.homepage = "http://github.com/rschultheis/hatt"
42
+ s.licenses = ["MIT"]
43
+ s.rubygems_version = "2.5.1"
44
+ s.summary = "Make calls to HTTP JSON APIs with ease and confidence"
45
+
46
+ if s.respond_to? :specification_version then
47
+ s.specification_version = 4
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
51
+ s.add_runtime_dependency(%q<faraday>, [">= 0"])
52
+ s.add_runtime_dependency(%q<multi_json>, [">= 0"])
53
+ s.add_runtime_dependency(%q<tcfg>, ["~> 0.2.2"])
54
+ s.add_runtime_dependency(%q<typhoeus>, [">= 0"])
55
+ s.add_runtime_dependency(%q<pry>, [">= 0"])
56
+ s.add_runtime_dependency(%q<awesome_print>, [">= 0"])
57
+ s.add_development_dependency(%q<debase>, [">= 0"])
58
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
59
+ s.add_development_dependency(%q<rspec>, [">= 0"])
60
+ s.add_development_dependency(%q<rubocop>, [">= 0"])
61
+ s.add_development_dependency(%q<ruby-debug-ide>, [">= 0"])
62
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<activesupport>, [">= 0"])
65
+ s.add_dependency(%q<faraday>, [">= 0"])
66
+ s.add_dependency(%q<multi_json>, [">= 0"])
67
+ s.add_dependency(%q<tcfg>, ["~> 0.2.2"])
68
+ s.add_dependency(%q<typhoeus>, [">= 0"])
69
+ s.add_dependency(%q<pry>, [">= 0"])
70
+ s.add_dependency(%q<awesome_print>, [">= 0"])
71
+ s.add_dependency(%q<debase>, [">= 0"])
72
+ s.add_dependency(%q<jeweler>, [">= 0"])
73
+ s.add_dependency(%q<rspec>, [">= 0"])
74
+ s.add_dependency(%q<rubocop>, [">= 0"])
75
+ s.add_dependency(%q<ruby-debug-ide>, [">= 0"])
76
+ s.add_dependency(%q<simplecov>, [">= 0"])
77
+ end
78
+ else
79
+ s.add_dependency(%q<activesupport>, [">= 0"])
80
+ s.add_dependency(%q<faraday>, [">= 0"])
81
+ s.add_dependency(%q<multi_json>, [">= 0"])
82
+ s.add_dependency(%q<tcfg>, ["~> 0.2.2"])
83
+ s.add_dependency(%q<typhoeus>, [">= 0"])
84
+ s.add_dependency(%q<pry>, [">= 0"])
85
+ s.add_dependency(%q<awesome_print>, [">= 0"])
86
+ s.add_dependency(%q<debase>, [">= 0"])
87
+ s.add_dependency(%q<jeweler>, [">= 0"])
88
+ s.add_dependency(%q<rspec>, [">= 0"])
89
+ s.add_dependency(%q<rubocop>, [">= 0"])
90
+ s.add_dependency(%q<ruby-debug-ide>, [">= 0"])
91
+ s.add_dependency(%q<simplecov>, [">= 0"])
92
+ end
93
+ end
94
+
@@ -0,0 +1,40 @@
1
+ require_relative 'http'
2
+ require_relative 'configuration'
3
+
4
+ module Hatt
5
+ module ApiClients
6
+ include Hatt::Configuration
7
+
8
+ def hatt_build_client_methods
9
+ hatt_configuration[:hatt_services].each_pair do |svc, svc_cfg|
10
+ hatt_add_service svc, svc_cfg
11
+ end
12
+ end
13
+
14
+ # add a service to hatt
15
+ #
16
+ # @param name [String] the name of the service
17
+ # @param url [String] an absolute url to the api
18
+ def hatt_add_service(name, url_or_svc_cfg_hash)
19
+ svc_cfg = case url_or_svc_cfg_hash
20
+ when String
21
+ { 'url' => url_or_svc_cfg_hash }
22
+ when Hash
23
+ url_or_svc_cfg_hash
24
+ else
25
+ raise ArgumentError, "'#{url_or_svc_cfg_hash}' is not a url string nor hash with url key"
26
+ end
27
+
28
+ init_config
29
+ services_config = hatt_configuration['hatt_services']
30
+ services_config[name] = svc_cfg
31
+ @hatt_configuration.tcfg_set 'hatt_services', services_config
32
+
33
+ @hatt_http_clients ||= {}
34
+ @hatt_http_clients[name] = Hatt::HTTP.new hatt_configuration['hatt_services'][name]
35
+ define_singleton_method name.intern do
36
+ @hatt_http_clients[name]
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/hatt/base.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'active_support'
2
+ require_relative 'mixin'
3
+ require_relative 'singleton_mixin'
4
+
5
+ module Hatt
6
+ class << self
7
+ include Hatt::Mixin
8
+
9
+ def new(options = {})
10
+ options = ActiveSupport::HashWithIndifferentAccess.new options
11
+ hatt_instance = Class.new { include Hatt::Mixin }.new
12
+ hatt_instance.hatt_config_file options.fetch(:config_file, 'hatt.yml')
13
+ hatt_instance.hatt_initialize
14
+ hatt_instance
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ module Hatt
2
+ # A simple 'blankslate' class which is used to avoid namespace polution
3
+ # Provides a proxy to a parent class, in order to allow access to other hatt methods like http service objects
4
+ #
5
+ # TODO: Figure out if can/should use a BasicObject here. I know it wont work right now
6
+ # because the binding method of Object is needed and not in BasicObject
7
+ #
8
+ class BlankSlateProxy < Object
9
+ def initialize(parent)
10
+ @parent = parent
11
+ end
12
+
13
+ def method_missing(method_id, *arguments, &block)
14
+ if parent_has_method?(method_id)
15
+ @parent.send(method_id, *arguments, &block)
16
+ else
17
+ super
18
+ end
19
+ end
20
+
21
+ def parent_has_method?(name, include_private = false)
22
+ if include_private
23
+ @parent.methods.include?(name.to_sym)
24
+ else
25
+ @parent.public_methods.include?(name.to_sym)
26
+ end
27
+ end
28
+
29
+ def respond_to_missing?(name, include_private = false)
30
+ parent_has_method?(name, include_private) || super
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,85 @@
1
+ require 'uri'
2
+
3
+ require 'tcfg/tcfg_base'
4
+
5
+ module Hatt
6
+ module Configuration
7
+ DEFAULT_CONFIG_FILE = 'hatt.yml'.freeze
8
+ DEFAULT_HATT_GLOBS = ['*_hattdsl/*_hattdsl.rb'].freeze
9
+
10
+ def hatt_configuration
11
+ init_config
12
+ @hatt_configuration.tcfg
13
+ end
14
+
15
+ def hatt_config_file=(filename)
16
+ @hatt_config_file = filename
17
+ init_config
18
+ self
19
+ end
20
+ alias hatt_config_file hatt_config_file=
21
+
22
+ private
23
+
24
+ def hatt_config_file_path
25
+ if instance_variable_defined? :@hatt_config_file and not @hatt_config_file.nil?
26
+ File.expand_path @hatt_config_file
27
+ elsif File.exist? DEFAULT_CONFIG_FILE
28
+ File.expand_path DEFAULT_CONFIG_FILE
29
+ else
30
+ nil
31
+ end
32
+ end
33
+
34
+ # ensure the configuration is resolved and ready to use
35
+ def init_config
36
+ unless instance_variable_defined? :@hatt_configuration
37
+ @hatt_configuration = TCFG::Base.new
38
+
39
+ # build up some default configuration
40
+ @hatt_configuration.tcfg_set 'hatt_services', {}
41
+ @hatt_configuration.tcfg_set 'hatt_globs', DEFAULT_HATT_GLOBS
42
+
43
+ @hatt_configuration.tcfg_set_env_var_prefix 'HATT_'
44
+ end
45
+
46
+ if hatt_config_file_path
47
+ # if a config file was specified, we assume it exists
48
+ @hatt_configuration.tcfg_config_file hatt_config_file_path
49
+ else
50
+ Log.warn 'No configuration file specified or found. Make a hatt.yml file and point hatt at it.'
51
+ end
52
+ @hatt_configuration.tcfg_set 'hatt_config_file', hatt_config_file_path
53
+
54
+ normalize_services_config @hatt_configuration
55
+
56
+ nil
57
+ end
58
+
59
+ def normalize_services_config(cfg)
60
+ services = cfg['hatt_services']
61
+ services.each_pair do |svc, svc_cfg|
62
+ # add the name
63
+ svc_cfg['name'] = svc
64
+
65
+ unless svc_cfg.key? :url
66
+ raise ConfigurationError, "url for service '#{svc_cfg['name']}' is not defined"
67
+ end
68
+
69
+ unless svc_cfg['url'] =~ URI::ABS_URI
70
+ raise ConfigurationError, "url for service '#{svc_cfg['name']}' is not a proper absolute URL: #{svc_cfg['url']}"
71
+ end
72
+
73
+ parsed = URI.parse svc_cfg['url']
74
+
75
+ svc_cfg['base_uri'] ||= parsed.path
76
+
77
+ svc_cfg['faraday_url'] = "#{parsed.scheme}://#{parsed.host}:#{parsed.port}"
78
+ end
79
+
80
+ cfg.tcfg_set 'hatt_services', services
81
+ end
82
+ end
83
+
84
+ class ConfigurationError < StandardError; end
85
+ end