gooddata 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (BSD License)
2
+
3
+ Copyright (c) 2010 Thomas Watson Steen & GoodData Corporation. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided
6
+ that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
9
+ the following disclaimer.
10
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
11
+ and the following disclaimer in the documentation and/or other materials provided with the distribution.
12
+ * Neither the name of the GoodData Corporation nor the names of its contributors may be used to endorse
13
+ or promote products derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
16
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
18
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,97 @@
1
+ = GoodData Ruby wrapper and CLI
2
+
3
+ A convenient Ruby wrapper around the GoodData RESTful API.
4
+
5
+ Use the Gooddata::Client class to integrate GoodData into your own application
6
+ or use the CLI to work with GoodData directly from the command line.
7
+
8
+ The best documentation for the API can be found using these resources:
9
+ * http://developer.gooddata.com/api
10
+ * https://secure.gooddata.com/gdc
11
+
12
+ == Usage
13
+
14
+ Since this project is in its early stages, no gem have been released to rubygems.org yet.
15
+ To install the gooddata gem, you instead have to first checkout this repository. Then install
16
+ the gem using the rake task:
17
+
18
+ rake install
19
+
20
+ Now you are ready to use either the Ruby wrapper class or the CLI.
21
+
22
+ Alternatively you can run the source code directly. For details about this approach, see {the
23
+ Development Wiki page}[http://github.com/gooddata/gooddata-ruby/wiki/Development].
24
+
25
+ === Wrapper class usage
26
+
27
+ For details of how to use the Ruby wrapper class, see the Gooddata::Client RDoc.
28
+
29
+ === CLI Usage
30
+
31
+ After installing the gooddata gem, GoodData is available from your command line using
32
+ the <tt>gooddata</tt> command. To get a complete overview of possible options type:
33
+
34
+ gooddata help
35
+
36
+ The examples and descriptions below does not cover all the options available via the CLI.
37
+ So remember to refer back to the <tt>help</tt> command.
38
+
39
+ Before you do anything else, a good idea is to see if your account is set up correctly and
40
+ that you can log in. To do this, use the <tt>api:test</tt> command:
41
+
42
+ gooddata api:test
43
+
44
+ ==== Authentication
45
+
46
+ As you saw if you ran the above test command <tt>gooddata</tt> will prompt you
47
+ for your GoodData username and password. If you don't wish to write your
48
+ credentials each time you connect to GoodData using <tt>gooddata</tt>, you can
49
+ create a simple gooddata credentials file called <tt>.gooddata</tt> in the root
50
+ of your home directory. To make it easy you can just run the credentials file
51
+ generator command which will create the file for you:
52
+
53
+ gooddata auth:store
54
+
55
+ ==== List available projects
56
+
57
+ To get a list of projects available to your GoodData user account, run:
58
+
59
+ gooddata projects
60
+
61
+ The output from the above command will look similar to this:
62
+
63
+ 521 Some project
64
+ 3521 Some other project
65
+ 3642 Some third project
66
+
67
+ The first column contains the project-key. You need this if you wan't to either
68
+ see more details about the project using the <tt>projects:show</tt> comamnd or
69
+ if you wish to delete the project using the <tt>projects:delete</tt> command.
70
+
71
+ ==== Create a new project
72
+
73
+ To create a new project under on the GoodData servers, run:
74
+
75
+ gooddata projects:create
76
+
77
+ You will then be asked about the desired project name and summary before it's created.
78
+
79
+ == Note on Patches/Pull Requests
80
+
81
+ * Fork the project.
82
+ * Make your feature addition or bug fix.
83
+ * Add tests for it. This is important so I don't break it in a
84
+ future version unintentionally.
85
+ * Commit, do not mess with rakefile, version, or history.
86
+ (if you want to have your own version, that is fine but bump version in a commit by itself we can ignore when we pull)
87
+ * Send us a pull request. Bonus points for topic branches.
88
+
89
+ == Credits
90
+
91
+ This project is developed and maintained by Pavel Kolesnikov [ mailto:pavel@gooddata.com
92
+ / {@koles}[http:/twitter.com/koles] ] and Thomas Watson Steen [ mailto:w@tson.dk /
93
+ {@wa7son}[http://twitter.com/wa7son] ]
94
+
95
+ == Copyright
96
+
97
+ Copyright (c) 2010 - 2011 GoodData Corporation and Thomas Watson Steen. See LICENSE for details.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'logger'
4
+
5
+ require 'gooddata'
6
+ require 'gooddata/command'
7
+
8
+ args = ARGV.dup
9
+ ARGV.clear
10
+ command = args.shift.strip rescue 'help'
11
+
12
+ GoodData.logger = Logger.new(STDOUT) if ENV['DEBUG']
13
+ GoodData::Command.run command, args
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gooddata'
4
+ require 'gooddata/command'
5
+
6
+ require 'irb'
7
+
8
+ include GoodData
9
+
10
+ module IRB
11
+ def IRB.start2(bind, ap_path)
12
+ IRB.setup(ap_path)
13
+ irb = Irb.new(WorkSpace.new(bind))
14
+ @CONF[:MAIN_CONTEXT] = irb.context
15
+ trap("SIGINT") do
16
+ irb.signal_handle
17
+ end
18
+ catch(:IRB_EXIT) do
19
+ irb.eval_input
20
+ end
21
+ end
22
+ end
23
+
24
+ param = ARGV.shift if ARGV.length
25
+ if param == '--debug' then
26
+ require 'logger'
27
+ GoodData.logger = Logger.new STDOUT
28
+ end
29
+ Command.connect
30
+ puts "Logged into GoodData as #{GoodData.profile.user} (#{GoodData.profile['login']})"
31
+ puts
32
+ IRB::start2 binding, $STDIN
33
+ puts "Logging out"
@@ -0,0 +1,3 @@
1
+ module GoodData; end
2
+
3
+ require 'gooddata/client'
@@ -0,0 +1,196 @@
1
+ require 'gooddata/version'
2
+ require 'gooddata/connection'
3
+ Dir[File.dirname(__FILE__) + '/models/*.rb'].each { |file| require file }
4
+ Dir[File.dirname(__FILE__) + '/collections/*.rb'].each { |file| require file }
5
+
6
+ # = GoodData API wrapper
7
+ #
8
+ # A convenient Ruby wrapper around the GoodData RESTful API.
9
+ #
10
+ # The best documentation for the API can be found using these resources:
11
+ # * http://developer.gooddata.com/api
12
+ # * https://secure.gooddata.com/gdc
13
+ #
14
+ # == Usage
15
+ #
16
+ # To communicate with the API you first need a personal GoodData account.
17
+ # {Sign up here}[https://secure.gooddata.com/registration.html] if you havent already.
18
+ #
19
+ # Now it is just a matter of initializing the GoodData connection via the connect
20
+ # method:
21
+ #
22
+ # GoodData.connect 'gooddata_user', 'gooddata_password'
23
+ #
24
+ # This GoodData object can now be utalized to retrieve your GoodData profile, the available
25
+ # projects etc.
26
+ #
27
+ # == Logging
28
+ #
29
+ # GoodData.logger = Logger.new(STDOUT)
30
+ #
31
+ # For details about the logger options and methods, see the
32
+ # {Logger module documentation}[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc].
33
+ #
34
+ module GoodData
35
+ module Threaded
36
+ # Used internally for thread safety
37
+ def threaded
38
+ Thread.current[:goooddata] ||= {}
39
+ end
40
+ end
41
+
42
+ class NilLogger
43
+ def debug(*args) ; end
44
+ alias :info :debug
45
+ alias :warn :debug
46
+ alias :error :debug
47
+ end
48
+
49
+ def project=(project)
50
+ GoodData.project = project
51
+ GoodData.project
52
+ end
53
+ alias :use :project=
54
+
55
+ class << self
56
+ include Threaded
57
+
58
+ RELEASE_INFO_PATH = '/gdc/releaseInfo'
59
+
60
+ def version
61
+ VERSION
62
+ end
63
+
64
+ def gem_version_string
65
+ "gooddata-gem/#{version}"
66
+ end
67
+
68
+ # Connect to the GoodData API
69
+ #
70
+ # === Parameters
71
+ #
72
+ # * +user+ - A GoodData username
73
+ # * +password+ - A GoodData password
74
+ #
75
+ def connect(user, password, url = nil)
76
+ threaded[:connection] = Connection.new user, password, url
77
+ end
78
+
79
+ # Returns the active GoodData connection earlier initialized via
80
+ # GoodData.connect call
81
+ #
82
+ # @see GoodData.connect
83
+ #
84
+ def connection
85
+ threaded[:connection]
86
+ end
87
+
88
+ # Sets the active project
89
+ #
90
+ # === Parameters
91
+ #
92
+ # * +project+ - a project identifier
93
+ #
94
+ # === Examples
95
+ #
96
+ # The following calls are equivalent:
97
+ # * GoodData.project = 'afawtv356b6usdfsdf34vt'
98
+ # * GoodData.use 'afawtv356b6usdfsdf34vt'
99
+ # * GoodData.use '/gdc/projects/afawtv356b6usdfsdf34vt'
100
+ # * GoodData.project = Project['afawtv356b6usdfsdf34vt']
101
+ #
102
+ def project=(project)
103
+ if project.is_a? Project
104
+ threaded[:project] = project
105
+ else
106
+ threaded[:project] = Project[project]
107
+ end
108
+ end
109
+
110
+ alias :use :project=
111
+
112
+ # Returns the active project
113
+ #
114
+ def project
115
+ threaded[:project]
116
+ end
117
+
118
+ # Performs a HTTP GET request.
119
+ #
120
+ # Retuns the JSON response formatted as a Hash object.
121
+ #
122
+ # === Parameters
123
+ #
124
+ # * +path+ - The HTTP path on the GoodData server (must be prefixed with a forward slash)
125
+ # === Examples
126
+ #
127
+ # GoodData.get '/gdc/projects'
128
+ def get(path)
129
+ connection.get(path)
130
+ end
131
+
132
+ # Performs a HTTP POST request.
133
+ #
134
+ # Retuns the JSON response formatted as a Hash object.
135
+ #
136
+ # === Parameters
137
+ #
138
+ # * +path+ - The HTTP path on the GoodData server (must be prefixed with a forward slash)
139
+ # * +data+ - The payload data in the format of a Hash object
140
+ #
141
+ # === Examples
142
+ #
143
+ # GoodData.post '/gdc/projects', { ... }
144
+ def post(path, data)
145
+ connection.post path, data
146
+ end
147
+
148
+ # Performs a HTTP DELETE request.
149
+ #
150
+ # Retuns the JSON response formatted as a Hash object.
151
+ #
152
+ # === Parameters
153
+ #
154
+ # * +path+ - The HTTP path on the GoodData server (must be prefixed with a forward slash)
155
+ #
156
+ # === Examples
157
+ #
158
+ # GoodData.delete '/gdc/project/1'
159
+ def delete(path)
160
+ connection.delete path
161
+ end
162
+
163
+ def test_login
164
+ connection.connect!
165
+ connection.logged_in?
166
+ end
167
+
168
+ # Returns the currently logged in user Profile.
169
+ def profile
170
+ threaded[:profile] ||= Profile.load
171
+ end
172
+
173
+ # Returns information about the GoodData API as a Hash (e.g. version, release time etc.)
174
+ def release_info
175
+ @release_info ||= @connection.get(RELEASE_INFO_PATH)['release']
176
+ end
177
+
178
+ # Returns the logger instance. The default implementation
179
+ # does not log anything
180
+ # For some serious logging, set the logger instance using
181
+ # the logger= method
182
+ #
183
+ # === Example
184
+ #
185
+ # require 'logger'
186
+ # GoodData.logger = Logger.new(STDOUT)
187
+ def logger
188
+ @logger ||= NilLogger.new
189
+ end
190
+
191
+ # Sets the logger instance
192
+ def logger=(logger)
193
+ @logger = logger
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,75 @@
1
+ require 'pp'
2
+ require 'gooddata/helpers'
3
+ require 'gooddata/commands/base'
4
+ Dir[File.dirname(__FILE__) + '/commands/*.rb'].each { |file| require file unless file =~ /\/base.rb$/ }
5
+
6
+ module GoodData::Command
7
+ class InvalidCommand < RuntimeError; end
8
+ class InvalidOption < RuntimeError; end
9
+ class CommandFailed < RuntimeError; end
10
+
11
+ extend GoodData::Helpers
12
+
13
+ class << self
14
+ def run(command, args)
15
+ begin
16
+ run_internal command, args.dup
17
+ rescue InvalidCommand
18
+ error "Unknown command. Run 'gooddata help' for usage information."
19
+ rescue InvalidOption
20
+ error "Unknown option."
21
+ rescue RestClient::Unauthorized
22
+ error "Authentication failure"
23
+ rescue RestClient::ResourceNotFound => e
24
+ error extract_not_found(e.http_body)
25
+ rescue RestClient::RequestFailed => e
26
+ error extract_error(e.http_body)
27
+ rescue RestClient::RequestTimeout
28
+ error "API request timed out. Please try again, or contact support@gooddata.com if this issue persists."
29
+ rescue CommandFailed => e
30
+ error e.message
31
+ rescue Interrupt => e
32
+ error "\n[canceled]"
33
+ end
34
+ end
35
+
36
+ def run_internal(command, args)
37
+ klass, method = parse(command)
38
+ runner = klass.new(args)
39
+ raise InvalidCommand unless runner.respond_to?(method)
40
+ runner.send(method)
41
+ end
42
+
43
+ def parse(command)
44
+ parts = command.split(':')
45
+
46
+ parts << :index if parts.size == 1
47
+ raise InvalidCommand if parts.size > 2
48
+
49
+ begin
50
+ return GoodData::Command.const_get(parts[0].capitalize), parts[1]
51
+ rescue NameError
52
+ raise InvalidCommand
53
+ end
54
+ end
55
+
56
+ def extract_not_found(body)
57
+ body =~ /^[\w\s]+ not found$/ ? body : "Resource not found"
58
+ end
59
+
60
+ def extract_error(body)
61
+ msg = parse_error_json(body) || 'Internal server error'
62
+ msg.split("\n").map { |line| ' ! ' + line }.join("\n")
63
+ end
64
+
65
+ def parse_error_json(body)
66
+ begin
67
+ error = JSON.parse(body.to_s)['error']
68
+ return error['message'] if !error['parameters']
69
+ return error['message'] % error['parameters'] rescue error
70
+ rescue
71
+ return body
72
+ end
73
+ end
74
+ end
75
+ end