hatt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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