gooddata 0.6.6 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{CHANGELOG.markdown → CHANGELOG.md} +6 -1
- data/lib/gooddata/cli/commands/project_cmd.rb +6 -29
- data/lib/gooddata/commands/project.rb +36 -44
- data/lib/gooddata/connection.rb +7 -0
- data/lib/gooddata/core/connection.rb +3 -0
- data/lib/gooddata/core/rest.rb +38 -19
- data/lib/gooddata/mixins/md_object_query.rb +3 -2
- data/lib/gooddata/models/metadata/dashboard.rb +3 -8
- data/lib/gooddata/models/metadata/report.rb +1 -6
- data/lib/gooddata/models/model.rb +5 -4
- data/lib/gooddata/models/process.rb +10 -14
- data/lib/gooddata/models/project.rb +34 -26
- data/lib/gooddata/models/project_blueprint.rb +14 -7
- data/lib/gooddata/models/project_creator.rb +2 -6
- data/lib/gooddata/models/schedule.rb +13 -2
- data/lib/gooddata/version.rb +1 -1
- data/spec/data/ruby_process/deep_files/deep_stuff.txt +1 -0
- data/spec/data/ruby_process/process.rb +2 -0
- data/spec/data/ruby_process/stuff.txt +1 -0
- data/spec/integration/full_process_schedule_spec.rb +69 -0
- data/spec/integration/full_project_spec.rb +14 -5
- data/spec/unit/models/schedule_spec.rb +7 -30
- metadata +7 -66
- data/doc/.gitignore +0 -1
- data/doc/css/.gitkeepme +0 -1
- data/doc/images/.gitkeepme +0 -1
- data/doc/images/background.png +0 -0
- data/doc/images/bg-callout-button.png +0 -0
- data/doc/images/header-logo.png +0 -0
- data/doc/images/logo-image.png +0 -0
- data/doc/js/.gitkeepme +0 -1
- data/doc/pages/GET_STARTED.md +0 -310
- data/doc/pages/HOMEPAGE.md +0 -77
- data/doc/pages/TUTORIALS.md +0 -52
- data/doc/pages/tutorial/BRICKS.md +0 -260
- data/doc/pages/tutorial/CREATING_A_MODEL.md +0 -81
- data/doc/pages/tutorial/CRUNCHING_NUMBERS.md +0 -231
- data/doc/pages/tutorial/TEST_DRIVEN_DEVELOPMENT.md +0 -120
- data/doc/pages/tutorial/YOUR_FIRST_PROJECT.md +0 -53
- data/doc/templates/default/class/dot/setup.rb +0 -6
- data/doc/templates/default/class/dot/superklass.erb +0 -3
- data/doc/templates/default/class/setup.rb +0 -37
- data/doc/templates/default/class/text/setup.rb +0 -11
- data/doc/templates/default/class/text/subclasses.erb +0 -5
- data/doc/templates/default/constant/text/header.erb +0 -11
- data/doc/templates/default/constant/text/setup.rb +0 -3
- data/doc/templates/default/docstring/setup.rb +0 -51
- data/doc/templates/default/docstring/text/abstract.erb +0 -2
- data/doc/templates/default/docstring/text/deprecated.erb +0 -2
- data/doc/templates/default/docstring/text/index.erb +0 -2
- data/doc/templates/default/docstring/text/note.erb +0 -4
- data/doc/templates/default/docstring/text/private.erb +0 -2
- data/doc/templates/default/docstring/text/returns_void.erb +0 -1
- data/doc/templates/default/docstring/text/text.erb +0 -1
- data/doc/templates/default/docstring/text/todo.erb +0 -4
- data/doc/templates/default/layout/dot/header.erb +0 -6
- data/doc/templates/default/layout/dot/setup.rb +0 -14
- data/doc/templates/default/method/setup.rb +0 -3
- data/doc/templates/default/method/text/header.erb +0 -1
- data/doc/templates/default/method_details/setup.rb +0 -11
- data/doc/templates/default/method_details/text/header.erb +0 -10
- data/doc/templates/default/method_details/text/method_signature.erb +0 -12
- data/doc/templates/default/method_details/text/setup.rb +0 -10
- data/doc/templates/default/module/dot/child.erb +0 -1
- data/doc/templates/default/module/dot/dependencies.erb +0 -3
- data/doc/templates/default/module/dot/header.erb +0 -6
- data/doc/templates/default/module/dot/info.erb +0 -14
- data/doc/templates/default/module/dot/setup.rb +0 -14
- data/doc/templates/default/module/setup.rb +0 -164
- data/doc/templates/default/module/text/children.erb +0 -10
- data/doc/templates/default/module/text/class_meths_list.erb +0 -8
- data/doc/templates/default/module/text/extends.erb +0 -8
- data/doc/templates/default/module/text/header.erb +0 -7
- data/doc/templates/default/module/text/includes.erb +0 -8
- data/doc/templates/default/module/text/instance_meths_list.erb +0 -8
- data/doc/templates/default/module/text/setup.rb +0 -12
- data/doc/templates/default/root/dot/child.erb +0 -3
- data/doc/templates/default/root/dot/setup.rb +0 -5
- data/doc/templates/default/tags/setup.rb +0 -55
- data/doc/templates/default/tags/text/example.erb +0 -12
- data/doc/templates/default/tags/text/index.erb +0 -1
- data/doc/templates/default/tags/text/option.erb +0 -20
- data/doc/templates/default/tags/text/overload.erb +0 -19
- data/doc/templates/default/tags/text/see.erb +0 -11
- data/doc/templates/default/tags/text/tag.erb +0 -13
@@ -1,231 +0,0 @@
|
|
1
|
-
# @title Crunching Numbers
|
2
|
-
|
3
|
-
MAQL is a language that is fairly similar to SQL but it is aimed towards getting the data from OLAP system. You are never forced to talk about columns and specify joins explicitly. This is great but there are some drawbacks. Same as SQL MAQL is aimed towards users more than machines which does not help for automation but there is one more caveat that make it hard to use even for humans. Probably to your surprise
|
4
|
-
|
5
|
-
SELECT SUM(Amount)
|
6
|
-
|
7
|
-
Is not a MAQL statement (even though you probably have seen this on UI). The more correct (and what goes back and forth over the wire) is
|
8
|
-
|
9
|
-
SELECT SUM([/gdc/md/132131231/obj/1])
|
10
|
-
|
11
|
-
GoodData UI does a great job at hiding this complexity from you but this significantly hinders the use of MAQL over and API by regular Joes. Ruby SDK tries to alleviate the situation with some tricks. It also gives you many tools to programmatically define and deal with reports and lays the foundations for test driven BI.
|
12
|
-
|
13
|
-
### Jack in
|
14
|
-
If you do not have a project best would be to create one by following our tutorial [Your first project](http://sdk.gooddata.com/gooddata-ruby/recipe/2014/01/19/your-first-project.html) so you can get predictable results.
|
15
|
-
|
16
|
-
First let's look around. There are no metrics
|
17
|
-
|
18
|
-
GoodData::Metric[:all]
|
19
|
-
> []
|
20
|
-
|
21
|
-
there is one fact
|
22
|
-
|
23
|
-
GoodData::Fact[:all]
|
24
|
-
> [{"link"=>"/gdc/md/ptbedvc1841r4obgptywd2mzhbwjsfyr/obj/223",
|
25
|
-
"author"=>"/gdc/account/profile/4e1e8cacc4989228e0ae531b30853248",
|
26
|
-
"tags"=>"",
|
27
|
-
"created"=>"2014-02-18 07:44:26",
|
28
|
-
"deprecated"=>"0",
|
29
|
-
"summary"=>"",
|
30
|
-
"title"=>"Lines changed",
|
31
|
-
"category"=>"fact",
|
32
|
-
"updated"=>"2014-02-18 07:44:26",
|
33
|
-
"contributor"=>"/gdc/account/profile/4e1e8cacc4989228e0ae531b30853248"}]
|
34
|
-
|
35
|
-
### First metric
|
36
|
-
Let's create our first metric. There are couple of ways so I will show them one by one. Regardless of how you create the metric the result is the same so pick the one that suits your style or situation.
|
37
|
-
|
38
|
-
TBD(add identifier based metric)
|
39
|
-
|
40
|
-
m = GoodData::Metric.create("SELECT SUM([/gdc/md/ptbedvc1841r4obgptywd2mzhbwjsfyr/obj/223])")
|
41
|
-
|
42
|
-
You can do it like this but obviously this is the ugly verbose way.
|
43
|
-
|
44
|
-
m = GoodData::Metric.xcreate('SELECT SUM(#"Lines changed")')
|
45
|
-
|
46
|
-
Here you are using the name of the fact. Let's notice couple of things. First we are not using create any more. Method xcreate stands for eXtended notation and tries to turn it into valid MAQL. When you are specifying the fact you are doing it using #"NAME".
|
47
|
-
|
48
|
-
Regardless of which way you used you have a metric definition. Metric is only locally on your computer we haven't saved it yet. Let's do it.
|
49
|
-
|
50
|
-
m.save
|
51
|
-
> RuntimeError: Meric needs to have title
|
52
|
-
|
53
|
-
Uh ok. You have two options
|
54
|
-
|
55
|
-
m.title = "My shiny metric"
|
56
|
-
|
57
|
-
or
|
58
|
-
|
59
|
-
m = GoodData::Metric.xcreate(:title => "My shiny metric", :expression => 'SELECT SUM(#"Lines changed")')
|
60
|
-
|
61
|
-
Go ahead and try saving it again.
|
62
|
-
|
63
|
-
m.save
|
64
|
-
> #<GoodData::Metric:0x007f95b609b548 ....
|
65
|
-
|
66
|
-
Great, looks good. Let's see if it worked
|
67
|
-
|
68
|
-
m.saved?
|
69
|
-
> true
|
70
|
-
|
71
|
-
m.uri
|
72
|
-
> "/gdc/md/ptbedvc1841r4obgptywd2mzhbwjsfyr/obj/292"
|
73
|
-
|
74
|
-
Let's get some numbers. You can execute the metric.
|
75
|
-
|
76
|
-
m.execute
|
77
|
-
> 9.0
|
78
|
-
|
79
|
-
Fantastic. You just created your first report over API.
|
80
|
-
|
81
|
-
### More on metric execution
|
82
|
-
|
83
|
-
Maybe you are wondering if you cannot just execute stuff to poke around. Well you kinda can. The API does not allow to execute a metric without it is saved (but we hope this will change soon). SDK tries to hide this from you but sometimes you can see the wiring. Let's explore. This is our well known metric
|
84
|
-
|
85
|
-
m = GoodData::Metric.xcreate('SELECT SUM(#"Lines changed")')
|
86
|
-
|
87
|
-
Let's try executing it
|
88
|
-
|
89
|
-
m.execute
|
90
|
-
> 9
|
91
|
-
|
92
|
-
It works. What happens behind the scenes is that SDK saves the metric and then deletes it again. It should mostly work
|
93
|
-
|
94
|
-
m.is_saved?
|
95
|
-
> false
|
96
|
-
|
97
|
-
m.uri
|
98
|
-
> nil
|
99
|
-
|
100
|
-
But sometimes you can see some inconsistencies.
|
101
|
-
|
102
|
-
m.title
|
103
|
-
> "Untitled metric"
|
104
|
-
|
105
|
-
This should not stop you most of the time. Just keep this in mind. Hopefully it will go completely away soon.
|
106
|
-
|
107
|
-
### Defining a ReportDefinition
|
108
|
-
|
109
|
-
Ok we have our metric. Now it would be interesting to see a report. The metric broken down. If you are familiar with the model you know the metric is a summation of lines changed in all commits in all products made by all developers. Let's see, how developers contributed.
|
110
|
-
|
111
|
-
GoodData::ReportDefinition.execute(:top => ["attr.devs.id"], :left => [m])
|
112
|
-
> [ 1 | 2 | 3 ]
|
113
|
-
[1.0 | 3.0 | 5.0]
|
114
|
-
|
115
|
-
Again, there are a lots of ways how to achieve the same result so let's have a look at what is available right now. You can already see that you can see a metric by reference and attribute can be referenced just by a string containing an identifier. Let's pass the attribute as an object as well.
|
116
|
-
|
117
|
-
a = GoodData::Attribute.get_by_id("attr.devs.id")
|
118
|
-
GoodData::ReportDefinition.execute(:top => [a], :left => [m])
|
119
|
-
|
120
|
-
If you studied UI well you know that Report is defined using Display Forms (or labels) not by attribute. If you are specifying an attribute SDK will take the first one automatically. This works well most of the time since attributes have typically just one label. But sometimes they have many so you need to me more specific. Coincidently our attribute has 2 labels.
|
121
|
-
|
122
|
-
a.display_forms.count
|
123
|
-
> 2
|
124
|
-
|
125
|
-
The identifiers are "label.devs.email" and "label.devs.id". Let's try using those
|
126
|
-
|
127
|
-
GoodData::ReportDefinition.execute(:top => ["label.devs.id"], :left => [m])
|
128
|
-
GoodData::ReportDefinition.execute(:top => ["label.devs.email"], :left => [m])
|
129
|
-
|
130
|
-
You can even do something that you cannot do on UI and that is using both of the labels at the same time (sic).
|
131
|
-
|
132
|
-
GoodData::ReportDefinition.execute(:top => ["label.devs.id", "label.devs.email"], :left => [m])
|
133
|
-
|
134
|
-
In almost all above cases we had only one thing in left or top section. You can save your fingers and not use the array literal if there is only one item in the section. SDK will wrap them for you.
|
135
|
-
|
136
|
-
GoodData::ReportDefinition.execute(:top => "label.devs.id", :left => m)
|
137
|
-
|
138
|
-
Sometimes it might be useful to refer to the objects in a different way. You can do it by title
|
139
|
-
|
140
|
-
GoodData::ReportDefinition.execute(
|
141
|
-
:top => [{:type => :attribute, :title => "Month/Year (committed_on)"}],
|
142
|
-
:left => m)
|
143
|
-
|
144
|
-
Since underneath it uses MdObject.find_first_by_title it also accepts RegExp literal
|
145
|
-
|
146
|
-
GoodData::ReportDefinition.execute(
|
147
|
-
:top => [{:type => :attribute, :title => /Month\/Year/}],
|
148
|
-
:left => m)
|
149
|
-
|
150
|
-
GoodData::ReportDefinition.execute(
|
151
|
-
:top => [{:type => :attribute, :title => /month\/year/i}],
|
152
|
-
:left => m)
|
153
|
-
|
154
|
-
In our model we have two attributes of name Id. Since the title does not have to be unique this is ok. Currently it will pick the first for you but this behavior will likely change in the favor of throwing an ambiguous error much like your SQL client probably does.
|
155
|
-
|
156
|
-
GoodData::ReportDefinition.execute(:top => [{:type => :attribute, :title => "Id"}], :left => m)
|
157
|
-
|
158
|
-
Of course you can combine all things we learned together.
|
159
|
-
|
160
|
-
a = GoodData::Attribute.find_first_by_title(/month\/year/i)
|
161
|
-
GoodData::ReportDefinition.execute(:top => [{:type => :attribute, :title => "Id"}], :left => [m, a])
|
162
|
-
|
163
|
-
### Reports
|
164
|
-
Up until now we have been computing the reports just because. Maybe you wonder how you can actually create a report that would be saved. It is simple
|
165
|
-
|
166
|
-
GoodData::ReportDefinition.execute(
|
167
|
-
:top => [{:type => :attribute, :title => /Month\/Year/}],
|
168
|
-
:left => m)
|
169
|
-
|
170
|
-
report = GoodData::Report.create(
|
171
|
-
:title => "Fantastic report",
|
172
|
-
:top => [{:type => :attribute, :title => /Month\/Year/}],
|
173
|
-
:left => m)
|
174
|
-
|
175
|
-
report.save
|
176
|
-
|
177
|
-
### Results
|
178
|
-
|
179
|
-
Ok now we know how to create a report. Now let's see what we can do with the result. The point of this framework is not only you being able to create reports programmatically and save them for consumption over UI. Yes this is incredibly useful but when we have that why stop there. With Ruby SDK you can actually consume the result programmatically as well so you can use GD as a basis for your application. Or as we show in this section we build a foundation for Test Driven BI development.
|
180
|
-
|
181
|
-
Let's execute one of the previously defined reports and this time let's store the result
|
182
|
-
|
183
|
-
result = GoodData::ReportDefinition.execute(
|
184
|
-
:top => [{:type => :attribute, :title => /month\/year/i}],
|
185
|
-
:left => m)
|
186
|
-
>
|
187
|
-
[Jan 2014 | Feb 2014]
|
188
|
-
[1.0 | 8.0 ]
|
189
|
-
|
190
|
-
The class is ReportDataResult. As you will see further it tries to conform to API of an array in key aspoects
|
191
|
-
|
192
|
-
result.class
|
193
|
-
> GoodData::ReportDataResult
|
194
|
-
|
195
|
-
result[0][0]
|
196
|
-
> "Jan 2014"
|
197
|
-
|
198
|
-
result[1][0]
|
199
|
-
> 1.0
|
200
|
-
|
201
|
-
All the numbers are of BigDecimal class so you should be able to perform additional computations without losing precision
|
202
|
-
|
203
|
-
result[1][0].class
|
204
|
-
> BigDecimal
|
205
|
-
|
206
|
-
Let's look on couple of methods that are useful for validating the results of reports
|
207
|
-
|
208
|
-
result.include_row? [1, 8]
|
209
|
-
> true
|
210
|
-
|
211
|
-
result.include_column? ["Feb 2014", 8]
|
212
|
-
> true
|
213
|
-
|
214
|
-
Result is coming from server in a special format but after some processing it is just an 2 D array so it is no wonder that you can test on equality of a whole report.
|
215
|
-
|
216
|
-
result == [["Jan 2014", "Feb 2014"], [1, 8]]
|
217
|
-
|
218
|
-
<div class="section-nav">
|
219
|
-
<div class="left align-right">
|
220
|
-
<a href="/docs/file/doc/pages/tutorial/CREATING_A_MODEL.md" class="prev">
|
221
|
-
Back
|
222
|
-
</a>
|
223
|
-
</div>
|
224
|
-
|
225
|
-
<div class="right align-left">
|
226
|
-
<a href="/docs/file/doc/pages/tutorial/TEST_DRIVEN_DEVELOPMENT.md" class="next">
|
227
|
-
Next
|
228
|
-
</a>
|
229
|
-
</div>
|
230
|
-
<div class="clear"></div
|
231
|
-
</div>
|
@@ -1,120 +0,0 @@
|
|
1
|
-
# @title Test Driven Development
|
2
|
-
|
3
|
-
Test driven development is a holy grail for many developers. It gives you an additional sense of security and you can rely on the test suite to give you a safety net when you are refactoring and tweaking existing code. Testing reports was hard until now.
|
4
|
-
|
5
|
-
## The model
|
6
|
-
Let's reuse the model that we have from model. Create a file called model.rb and put this inside.
|
7
|
-
|
8
|
-
GoodData::Model::ProjectBuilder.create("gooddata-ruby test #{Time.now.to_i}") do |p|
|
9
|
-
p.add_date_dimension("closed_date")
|
10
|
-
|
11
|
-
p.add_dataset("users") do |d|
|
12
|
-
d.add_anchor("id")
|
13
|
-
d.add_label("name", :reference => 'id')
|
14
|
-
end
|
15
|
-
|
16
|
-
p.add_dataset("regions") do |d|
|
17
|
-
d.add_anchor("id")
|
18
|
-
d.add_attribute("name")
|
19
|
-
end
|
20
|
-
|
21
|
-
p.add_dataset("opportunities") do |d|
|
22
|
-
d.add_fact("amount")
|
23
|
-
d.add_date("closed_date", :dataset => "closed_date")
|
24
|
-
d.add_reference("user_id", :dataset => 'users', :reference => 'id')
|
25
|
-
d.add_reference("region_id", :dataset => 'regions', :reference => 'id')
|
26
|
-
end
|
27
|
-
|
28
|
-
p.add_metric({
|
29
|
-
"title": "Sum Amount",
|
30
|
-
"expression": "SELECT SUM(#\"amount\") + 1",
|
31
|
-
"extended_notation": true
|
32
|
-
})
|
33
|
-
|
34
|
-
p.upload([["id", "name"],
|
35
|
-
["1", "Tomas"],
|
36
|
-
["2", "Petr"]], :dataset => 'users')
|
37
|
-
|
38
|
-
p.upload([["id", "name"],
|
39
|
-
["1", "Tomas"],
|
40
|
-
["2", "Petr"]], :dataset => 'regions')
|
41
|
-
end
|
42
|
-
|
43
|
-
## The test
|
44
|
-
Let's say that you have some not so simple metric and you want to test it so you make sure it works as expected. The easiest way to do it is create a testing project and prepare some made up data and then spin it. You already know how to create a model and load data let's talk about how to define test cases.
|
45
|
-
|
46
|
-
The trick is to use assert_report helper. This means that the report will be executed and if the result will be different it will fail. The helper takes 2 parameters. First is a report definition second is the result expected. Currently it stops on the first failure but this will change soon and we will run all the tests and collect the results.
|
47
|
-
|
48
|
-
p.assert_report({:top => [{:type => :metric, :title => "Sum Amount"}]}, [["3"]])
|
49
|
-
|
50
|
-
|
51
|
-
Go ahead and test it out
|
52
|
-
|
53
|
-
gooddata --username joe@example.com --password my_secret_pass --token my_token project build model.rb
|
54
|
-
|
55
|
-
|
56
|
-
## Production
|
57
|
-
|
58
|
-
The way we have it set up right now nothing forces us to use the same metrics to build the report. This is a problem. Ideally we wanna make sure that the same report in test project is then used in production and if somebody changes the project because the business requirements changes we want the same report to be used in the test and if something fails we want to know.
|
59
|
-
|
60
|
-
This is easiest to achieve by extracting the metrics and the model to separate file that can later be used when describing the project. You can then reference the same file form your production and testing project and make sure they are build using the same source.
|
61
|
-
|
62
|
-
The description might look something like this
|
63
|
-
|
64
|
-
GoodData::Model::ProjectBuilder.create("gooddata-ruby test #{Time.now.to_i}") do |p|
|
65
|
-
p.add_date_dimension("closed_date")
|
66
|
-
|
67
|
-
p.add_dataset("users") do |d|
|
68
|
-
d.add_anchor("id")
|
69
|
-
d.add_label("name", :reference => 'id')
|
70
|
-
end
|
71
|
-
|
72
|
-
p.add_dataset("regions") do |d|
|
73
|
-
d.add_anchor("id")
|
74
|
-
d.add_attribute("name")
|
75
|
-
end
|
76
|
-
|
77
|
-
p.add_dataset("opportunities") do |d|
|
78
|
-
d.add_fact("amount")
|
79
|
-
d.add_date("closed_date", :dataset => "closed_date")
|
80
|
-
d.add_reference("user_id", :dataset => 'users', :reference => 'id')
|
81
|
-
d.add_reference("region_id", :dataset => 'regions', :reference => 'id')
|
82
|
-
end
|
83
|
-
|
84
|
-
p.load_metrics('https://bit.ly/gd_demo_1_metrics')
|
85
|
-
|
86
|
-
p.upload([["id", "name"],
|
87
|
-
["1", "Tomas"],
|
88
|
-
["2", "Petr"]], :dataset => 'users')
|
89
|
-
|
90
|
-
p.upload([["id", "name"],
|
91
|
-
["1", "Tomas"],
|
92
|
-
["2", "Petr"]], :dataset => 'regions')
|
93
|
-
|
94
|
-
p.upload([["amount", "closed_date", "user_id", "region_id"],
|
95
|
-
["1", "2001/01/01", "1", "1"],
|
96
|
-
["1", "2001/01/01", "1", "2"]], :dataset => 'opportunities')
|
97
|
-
|
98
|
-
p.assert_report({:top => [{:type => :metric, :title => "Sum Amount"}]}, [["3"]])
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
Here we are externalizing only the metrics but you can hopefully see that it might make sense to do it for the model as well.
|
103
|
-
|
104
|
-
# Rinse repeat
|
105
|
-
If you have any experience with TDD you know that your tests have to run daily to have any effect. This is TBD :-)
|
106
|
-
|
107
|
-
<div class="section-nav">
|
108
|
-
<div class="left align-right">
|
109
|
-
<a href="/docs/file/doc/pages/tutorial/CRUNCHING_NUMBERS.md" class="prev">
|
110
|
-
Back
|
111
|
-
</a>
|
112
|
-
</div>
|
113
|
-
<div class="right align-left">
|
114
|
-
<a href="/docs/file/doc/pages/tutorial/BRICKS.md" class="next">
|
115
|
-
Next
|
116
|
-
</a>
|
117
|
-
</div>
|
118
|
-
<div class="clear"></div>
|
119
|
-
</div>
|
120
|
-
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# @title Your First Project
|
2
|
-
|
3
|
-
Ok welcome. Let's spin up an example project that we created so you can explore and see SDK in action. It is super simple. Since you are probably a developer we created simple project about developers.
|
4
|
-
|
5
|
-
### What we want to measure
|
6
|
-
Imagine you have a small dev shop. You have couple of developers. They crank out code. You also have couple of repositories for products. You want to measure how many lines of code each of the devs create. you wanna be able to track it by time by repository and by person. You want to see how many lines of code they committed.
|
7
|
-
|
8
|
-
### Model
|
9
|
-
This is how the model looks.
|
10
|
-
|
11
|
-
![Model](https://dl.dropboxusercontent.com/s/1y97ziv5anmpn9s/gooddata_devs_demo_model.png?token_hash=AAENC89d8XOfCr9AnyQCrd9vwfhb-bDuYcORQ0AIRP2RQQ)
|
12
|
-
|
13
|
-
### Spinning it up
|
14
|
-
Let's do this. I assume you have gooddata SDK installed and working. Run
|
15
|
-
|
16
|
-
gooddata scaffold project my_test_project
|
17
|
-
|
18
|
-
go to the directory
|
19
|
-
|
20
|
-
cd my_test_project
|
21
|
-
|
22
|
-
and build project
|
23
|
-
|
24
|
-
gooddata -U username -P pass -t token project build
|
25
|
-
|
26
|
-
If everything goes ok it will give you a PID also called a project_id. Open the my_test_project directory in your favorite text editor and open file called Goodfile. It should look like this
|
27
|
-
|
28
|
-
{
|
29
|
-
"model" : "./model/model.rb",
|
30
|
-
"project_id" : ""
|
31
|
-
}
|
32
|
-
|
33
|
-
Put your freshly acquired pid into an empty slot after "project_id". It should look like this.
|
34
|
-
|
35
|
-
{
|
36
|
-
"model" : "./model/model.rb",
|
37
|
-
"project_id" : "HERE_COMES_YOUR NEW_TOKEN"
|
38
|
-
}
|
39
|
-
|
40
|
-
You are done. If you go to [https://secure.gooddata.com/projects.html](https://secure.gooddata.com/projects.html) you should be able to see your new project. Also locally you are ready for other tutorials
|
41
|
-
|
42
|
-
|
43
|
-
<div class="section-nav">
|
44
|
-
<div class="left align-right">
|
45
|
-
<span class="prev disabled">Back</span>
|
46
|
-
</div>
|
47
|
-
|
48
|
-
<div class="right align-left">
|
49
|
-
<a href="/docs/file/doc/pages/tutorial/CREATING_A_MODEL.md" class="next">Next</a>
|
50
|
-
</div>
|
51
|
-
|
52
|
-
<div class="clear"></div>
|
53
|
-
</div>
|
@@ -1,37 +0,0 @@
|
|
1
|
-
include T('default/module')
|
2
|
-
|
3
|
-
def init
|
4
|
-
super
|
5
|
-
sections.place(:subclasses).before(:children)
|
6
|
-
sections.place(:constructor_details, [T('method_details')]).before(:methodmissing)
|
7
|
-
sections.place(:specs).before(:children)
|
8
|
-
end
|
9
|
-
|
10
|
-
def constructor_details
|
11
|
-
ctors = object.meths(:inherited => true, :included => true)
|
12
|
-
return unless @ctor = ctors.find {|o| o.constructor? }
|
13
|
-
return if prune_method_listing([@ctor]).empty?
|
14
|
-
erb(:constructor_details)
|
15
|
-
end
|
16
|
-
|
17
|
-
def subclasses
|
18
|
-
return if object.path == "Object" # don't show subclasses for Object
|
19
|
-
unless globals.subclasses
|
20
|
-
globals.subclasses = {}
|
21
|
-
list = run_verifier Registry.all(:class)
|
22
|
-
list.each do |o|
|
23
|
-
(globals.subclasses[o.superclass.path] ||= []) << o if o.superclass
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
@subclasses = globals.subclasses[object.path]
|
28
|
-
return if @subclasses.nil? || @subclasses.empty?
|
29
|
-
@subclasses = @subclasses.sort_by {|o| o.path }.map do |child|
|
30
|
-
name = child.path
|
31
|
-
if object.namespace
|
32
|
-
name = object.relative_path(child)
|
33
|
-
end
|
34
|
-
[name, child]
|
35
|
-
end
|
36
|
-
erb(:subclasses)
|
37
|
-
end
|