gd_bam 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -35,6 +35,7 @@ You need a working project with API access. You should also have username pass a
35
35
  ### Warnings
36
36
  The project is currently cloned out of an existing project. That means that you need to have access to it. If you do not (the project PID is i49w4c73c2mh75iiehte3fv3fbos8h2k) ask svarovsky@gooddata.com. Eventually this will be covered by a template so you will not need to do anything special. The template creation is tracked here https://jira.intgdc.com/browse/GD-34641 .
37
37
 
38
+ ###Let's get to it
38
39
  We will spin a goodsales project and load it with data. Prerequisite for this is a functioning Salesforce poject that you can grab at force.com.
39
40
 
40
41
  `bam scaffold project test --blueprint goodsales`
@@ -58,7 +59,7 @@ We will talk in detail why we split etl for project into downloaders and rest of
58
59
 
59
60
  You can watch the progress in our CloudConnect console.
60
61
 
61
- Now generate the etl.
62
+ Now generate the etl.
62
63
 
63
64
  `bam generate`
64
65
 
@@ -68,8 +69,19 @@ This works the same as with downloaders but its default target is clover_project
68
69
 
69
70
  After it is finished log in to gooddata go into your project and celebrate. You just did project using BAM.
70
71
 
72
+ ##Painful metadata management
73
+ Key pain that I had with CloudConnect is that I hated the management of metadata. Every project I saw was just pile of metadata definition that has to be constantly changed and tweaked. This is caused by couple of chioces that creators of underlying Clover engine made in the beginning and probably will not be changed easily. While I am trying to make it better I am still bound by these choices and sometimes the wiring stick out - sorry for that.
74
+
75
+ ###Incremental metadata
76
+ Bam is working with something that is called Incremental metadata. Metadata is not defined in each step you just say what you want to change. Picture is probably better than thousand words.
77
+
78
+ You have a conceptual picture of a simple transformation. You get a Tap that downloads FirstName and LastName somewhere. Obviously you would like to join them together to form a name. Exactly this happens in the second box the transformer. You would like to sink the only field and that is name. So on the next edge what you say is "I am adding Name and removing FirstName and LastName". So far so good. What is elegant about this approach is that how it copes with change. Imagine that the tap gets not only FirstName and LastName but also Age. Now what you need to change? If you would do it the old way You would have to change metadata on both edges, tap transformer and sink. With incremental metadata you need to change tap and sink nothing else. Since I claim that dealing with metadata was the biggest pain this is a lot of work (and errors) that you just saved.
79
+
80
+ ###Types or not?
81
+ Clover engine is built on Java and it shows. It is statically typed and CTL Clover transformation language resembles Java a lot. While it helps speed and many people claim it prevents errors it also causes more work and helps metadata explosion. Sometimes you need to translate an field into another field becuase you need to do something specific or the component needs it. It is not problem per se but it is important to see the tradeoffs and push the functionality into the components that should work for you and not against you. It is also important to do certain tasks at certain phases. If you do this you found out that certain parts are easier to automate or you can easily reuse work that you did somewhere else.
82
+
71
83
  ##Taps
72
- Taps are sources of data. There are various types (:-)) but right now you can use just salesforce tap.
84
+ Taps are sources of data. Right now you can use just salesforce tap.
73
85
 
74
86
  ###Common properties
75
87
  Every tap has the source and an id. Source tells it where to go to grab data. DB, CSV, SalesForce. Depending on the type the definition might be different. Id is a field that holds a name with which you can reference particular tap. Obviously it needs to be unique.
@@ -155,10 +167,10 @@ Fail early. There is nothing more frustrating than when the ETL fails during exw
155
167
  ####Mandatory fields
156
168
  Sometimes it is necessary to move fields around in SF. In such case the tap will. If you know this upfront you can tell BAM that this field is not mandatory and it will silently go along filling the missing field with ''
157
169
 
158
- ###Sinks
170
+ ##Flows
171
+ Flow is an abstraction
159
172
 
160
-
161
- This tap will download users from sf (you have to provide credentials in params.json). It then runs graph called "process user" (this is part of the distribution). This graph concatenates first name and last name together.
173
+ This flow will download users from sf (you have to provide credentials in params.json). It then runs graph called "process user" (this is part of the distribution). This graph concatenates first name and last name together. It then feeds data to the sink.
162
174
 
163
175
  GoodData::CloverGenerator::DSL::flow("user") do |f|
164
176
  tap(:id => "user")
@@ -175,29 +187,59 @@ This tap will download users from sf (you have to provide credentials in params.
175
187
 
176
188
  Now you have to provide it the definition of tap which you can do like this.
177
189
 
190
+ ###When I call external graph? How does it work?
191
+ In the flow you can call external graph by using
178
192
 
193
+ graph('my_graph')
194
+
195
+ It goes to 2 places (this will change) and tries to find the graph. First place is your `local_graphs` directory in your project the second place is central reporsitory that is currently inside bam library and this part will probably change.
179
196
 
180
- Also you need to provide a definition for sink which can look somwhow like this.
197
+ ##Sinks
181
198
 
182
- {
183
- "type" : "dataset"
184
- ,"id" : "user"
185
- ,"gd_name" : "user"
186
- ,"fields" : [
187
- {
188
- "name" : "Id"
189
- },
190
- {
191
- "name" : "Name"
192
- }
193
- ]
194
- }
199
+ Sink is a definition of where data goes to. Currently there is only one sink type and that is gooddata dataset.
195
200
 
196
- For this example to work you need to provide SF and gd credentials. Provide them in params.json. You would need to provide also a project with appropriate project but this is out of scope of this "example" (I am working on tools that would make it easier).
201
+ ###GoodData
202
+
203
+ {
204
+ "type" : "dataset",
205
+ "id" : "account",
206
+ "gd_name" : "account",
207
+ "fields": [
208
+ {
209
+ "name" : "id",
210
+ "type" : "connection_point",
211
+ "meta" : "Id"
212
+ },
213
+ {
214
+ "type" : "label",
215
+ "for" : "id",
216
+ "name" : "name",
217
+ "meta" : "Name"
218
+ },
219
+ {
220
+ "type" : "label",
221
+ "for" : "id",
222
+ "name" : "url",
223
+ "meta" : "Url"
224
+ },
225
+ {
226
+ "name" : "market",
227
+ "type" : "attribute",
228
+ "meta" : "Market__c"
229
+ }
230
+ ]
231
+ }
232
+
233
+ Gooddat sink is currently just mimicking the CL tool definition + some shortcuts on top of that. If you are familiar with CL tool you should be right at home if I tell you that the only additional thing you have to provide is telling BAM which metadata field is pulled in to a given field.
234
+
235
+
236
+
237
+ <!--For this example to work you need to provide SF and gd credentials. Provide them in params.json. You would need to provide also a project with appropriate project but this is out of scope of this "example" (I am working on tools that would make it easier).
197
238
 
198
239
  Now run `bam generate` and there will be a folder with the clover project generated. Open it in CC find main.grf and run it. After crunching for a while you should see data in the project.
240
+ -->
199
241
 
200
- ### Runtime commands
242
+ ##Runtime commands
201
243
  Part of the distribution is the bam executable which lets you do several neat things on the commandline
202
244
 
203
245
  Run `bam` to get the list of commands
@@ -207,7 +249,7 @@ Run `bam help command` to get help about the command
207
249
  deploys the directory to the server. You can provide the param of the process as a parameter
208
250
 
209
251
  ### generate
210
- Generates the ETL. The default target directory is clover_project (currently cannot be changed). You can provide --only parameter to specify the name of the flow to be processed if you do not need to generate all flows. Currently you can specify only on in only param
252
+ Generates the ETL. The default target directory is clover_project (currently cannot be changed). You can provide --only parameter to specify the name of the flow to be processed if you do not need to generate all flows. Currently you can specify only one flow
211
253
 
212
254
  ### generate_downloaders
213
255
  If you have incremental downloaders in your project it good to deploy them as a separate process. This generates only the downloaders and is meant for exacltly this purpose. If you are interested about why it is a good idea. Take a look here (TBD). The target directory is downloaders_project (currently cannot be changed).
@@ -216,10 +258,11 @@ If you have incremental downloaders in your project it good to deploy them as a
216
258
  Investigates what is changed and performs the changes in the target project. Uses CL tool behind the scenes. Needs more work
217
259
 
218
260
  ### model_sync
219
- Syncs the model with the definition in sinks. {Todo} Add interactive addition. Sometimes the new field can actually be a typo or something like that. Possible to uncover with validate_datasets
261
+ Syncs the model with the definition in sinks. Sometimes the new field can actually be a typo or something like that. Possible to uncover with validate_datasets
220
262
 
221
263
  ### run
222
- TBD
264
+ Runs the project and
265
+ `bam run clover-project --email me@gooddata.com`
223
266
 
224
267
  ### scaffold
225
268
  Takes an argument and creates a scaffold for you. It can scaffold project, flow, sink and tap.
data/bin/bam CHANGED
@@ -31,6 +31,15 @@ command :generate do |c|
31
31
  end
32
32
  end
33
33
 
34
+ desc 'Jacks into SF.'
35
+ # arg_name 'Describe arguments to new here'
36
+ command :sf_jack_in do |c|
37
+
38
+ c.action do |global_options,options,args|
39
+ GoodData::CloverGenerator.sf_jack_in
40
+ end
41
+ end
42
+
34
43
  desc 'Generates clover project for downloaders.'
35
44
  # arg_name 'Describe arguments to new here'
36
45
  command :generate_downloaders do |c|
@@ -106,7 +115,8 @@ command :project do |c|
106
115
  when nil
107
116
  fail "Empty project not supported now"
108
117
  end
109
- GoodData::CloverGenerator.connect_to_gd
118
+
119
+ GoodData::CloverGenerator.connect_to_gd()
110
120
  with_users = options[:with_users]
111
121
 
112
122
  export = {
@@ -184,7 +194,7 @@ command :scaffold do |c|
184
194
 
185
195
  c.action do |global_options,options,args|
186
196
  command = args.first
187
- fail "You did not provide what I should scaffold. I can generate project, tap, flow, sink nothing else" unless ["project", "tap", "flow", "sink"].include?(command)
197
+ fail "You did not provide what I should scaffold. I can generate project, tap, flow, sink, graph_template nothing else" unless ["project", "tap", "flow", "sink", "graph_template"].include?(command)
188
198
  case command
189
199
  when "project"
190
200
  directory = args[1]
@@ -209,6 +219,12 @@ command :scaffold do |c|
209
219
  name = args[1]
210
220
  fail "Name of the sink has to be provided as an argument. See help" if name.nil?
211
221
  GoodData::CloverGenerator.setup_sink(name)
222
+ when "graph_template"
223
+ name = args[1]
224
+ target = args[2]
225
+ fail "Name of the template has to be provided as an argument. See help" if name.nil?
226
+ fail "Name of the target has to be provided as an argument. See help" if target.nil?
227
+ GoodData::CloverGenerator.generate_graph_template(name, target)
212
228
  end
213
229
  end
214
230
  end
@@ -262,13 +278,16 @@ command :run do |c|
262
278
 
263
279
  verbose = global_options[:v]
264
280
 
265
- GoodData::CloverGenerator.connect_to_gd
281
+ logger = Logger.new(STDOUT) if global_options[:l]
282
+
283
+
284
+ GoodData::CloverGenerator.connect_to_gd(:logger => logger)
266
285
  options = global_options.merge({:name => "temporary"})
267
286
  GoodData::CloverGenerator.deploy(dir, options) do |deploy_response|
268
287
  puts HighLine::color("Executing", HighLine::BOLD) if verbose
269
288
  GoodData::CloverGenerator.create_email_channel(options) do |channel_response|
270
- GoodData::CloverGenerator.subscribe_on_finish(:success, channel_response["channelConfiguration"]["meta"]["uri"], deploy_response["cloverTransformation"]["links"]["self"].split('/').last)
271
- GoodData::CloverGenerator.execute_process(deploy_response["cloverTransformation"]["links"]["executions"], dir)
289
+ GoodData::CloverGenerator.subscribe_on_finish(:success, channel_response["channelConfiguration"]["meta"]["uri"], deploy_response["process"]["links"]["self"].split('/').last)
290
+ GoodData::CloverGenerator.execute_process(deploy_response["process"]["links"]["executions"], dir)
272
291
  end
273
292
  end
274
293
  end
data/lib/bam/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Bam
2
- VERSION = '0.0.6'
2
+ VERSION = '0.0.7'
3
3
  end
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Graph author="fluke" created="Tue Feb 05 15:38:24 PST 2013" guiVersion="3.3.2" id="1360179808937" licenseType="Commercial" modified="Thu May 02 12:37:08 PDT 2013" modifiedBy="gdc-defectivedisplay" name="process_name" revision="1.14" showComponentDetails="true">
3
+ <Global>
4
+ <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_in.xml" id="Metadata0"/>
5
+ <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_out.xml" id="Metadata1"/>
6
+ <MetadataGroup id="ComponentGroup0" name="metadata"/>
7
+ <Property fileURL="params.txt" id="GraphParameter0"/>
8
+ <Property fileURL="workspace.prm" id="GraphParameter2"/>
9
+ <Dictionary/>
10
+ </Global>
11
+ <Phase number="0">
12
+ <Node enabled="enabled" fileURL="data/1_in.csv" guiHeight="77" guiName="CSV Reader" guiWidth="128" guiX="37" guiY="169" id="DATA_READER0" quoteCharacter="&quot;" quotedStrings="true" skipRows="1" type="DATA_READER"/>
13
+ <Node enabled="enabled" fileURL="data/out.csv" guiHeight="77" guiName="CSV Writer" guiWidth="128" guiX="609" guiY="169" id="DATA_WRITER0" outputFieldNames="true" quoteCharacter="&quot;" quotedStrings="true" type="DATA_WRITER"/>
14
+ <Node dedupKey="ForecastCategoryName(a)" enabled="enabled" guiHeight="65" guiName="Dedup" guiWidth="128" guiX="368" guiY="160" id="DEDUP0" type="DEDUP"/>
15
+ <Node enabled="enabled" guiHeight="89" guiName="ExtSort" guiWidth="128" guiX="199" guiY="175" id="EXT_SORT0" sortKey="ForecastCategoryName(a)" type="EXT_SORT"/>
16
+ <Edge fromNode="DATA_READER0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge0" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (output)" toNode="EXT_SORT0:0"/>
17
+ <Edge fromNode="DEDUP0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge1" inPort="Port 0 (in)" metadata="Metadata1" outPort="Port 0 (unique)" toNode="DATA_WRITER0:0"/>
18
+ <Edge fromNode="EXT_SORT0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge2" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (out)" toNode="DEDUP0:0"/>
19
+ </Phase>
20
+ </Graph>
@@ -0,0 +1,84 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Graph author="gdc-defectivedisplay" created="Sat Mar 16 12:07:29 PDT 2013" guiVersion="3.3.2" id="1363571865202" licenseCode="CLP1DGOODD71636137BY" licenseType="Commercial" modified="Thu Apr 11 13:57:16 PDT 2013" modifiedBy="Jagjit" name="xxxx" revision="1.55" showComponentDetails="true">
3
+ <Global>
4
+ <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_in.xml" id="Metadata0"/>
5
+ <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_out.xml" id="Metadata1"/>
6
+ <Metadata id="Metadata2">
7
+ <Record fieldDelimiter="|" name="recordName1" recordDelimiter="\n" type="delimited">
8
+ <Field name="field1" type="string"/>
9
+ </Record>
10
+ </Metadata>
11
+ <Property fileURL="params.txt" id="GraphParameter0"/>
12
+ <Property fileURL="workspace.prm" id="GraphParameter2"/>
13
+ <Dictionary/>
14
+ </Global>
15
+ <Phase number="0">
16
+ <Node enabled="enabled" fileURL="data/1_in.csv" guiHeight="77" guiName="CSV Reader" guiWidth="128" guiX="83" guiY="90" id="DATA_READER0" quoteCharacter="&quot;" quotedStrings="true" skipRows="1" type="DATA_READER"/>
17
+ <Node enabled="enabled" guiHeight="65" guiName="Reformat" guiWidth="128" guiX="282" guiY="80" id="REFORMAT1" type="REFORMAT">
18
+ <attr name="transform"><![CDATA[//#CTL2
19
+
20
+ // Transforms input record into output record.
21
+ function integer transform() {
22
+ $out.0.* = $in.0.*;
23
+
24
+ if ($in.0.Probability == null) {
25
+ $out.0.Probability = "0";
26
+ } else {
27
+ $out.0.Probability = toString(str2decimal($in.0.Probability)/100D);
28
+ }
29
+
30
+ if ($in.0.Amount == null) {
31
+ $out.0.Amount = "0";
32
+ } else {
33
+ $out.0.Amount = toString(round(str2decimal($in.0.Amount)*100D)/100D);
34
+ }
35
+
36
+ if ($in.0.CloseDate != null && $in.0.CloseDate != "" && left($in.0.CloseDate, 4) < "1950") {
37
+ $out.0.CloseDate = '1950-01-01';
38
+ }
39
+
40
+ if ($in.0.CloseDate != null && $in.0.CloseDate != "" && left($in.0.CloseDate, 4) > "2049") {
41
+ $out.0.CloseDate = '2049-01-01';
42
+ }
43
+
44
+ if ($in.0.CreatedDate != null && $in.0.CreatedDate != "" && left($in.0.CreatedDate, 4) < "1950") {
45
+ $out.0.CreatedDate = '1950-01-01';
46
+ }
47
+
48
+ if ($in.0.CreatedDate != null && $in.0.CreatedDate != "" && left($in.0.CreatedDate, 4) > "2049") {
49
+ $out.0.CreatedDate = '2049-01-01';
50
+ }
51
+
52
+ if ($in.0.CreatedDate != null && $in.0.CreatedDate != "" ) {
53
+ $out.0.CreatedDate = left($in.0.CreatedDate, 10);
54
+ }
55
+
56
+ return ALL;
57
+ }
58
+
59
+ // Called during component initialization.
60
+ // function boolean init() {}
61
+
62
+ // Called during each graph run before the transform is executed. May be used to allocate and initialize resources
63
+ // required by the transform. All resources allocated within this method should be released
64
+ // by the postExecute() method.
65
+ // function void preExecute() {}
66
+
67
+ // Called only if transform() throws an exception.
68
+ // function integer transformOnError(string errorMessage, string stackTrace) {}
69
+
70
+ // Called during each graph run after the entire transform was executed. Should be used to free any resources
71
+ // allocated within the preExecute() method.
72
+ // function void postExecute() {}
73
+
74
+ // Called to return a user-defined error message when an error occurs.
75
+ // function string getMessage() {}
76
+ ]]></attr>
77
+ </Node>
78
+ <Edge fromNode="DATA_READER0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge1" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (output)" toNode="REFORMAT1:0"/>
79
+ <Edge fromNode="REFORMAT1:0" guiBendpoints="" guiRouter="Manhattan" id="Edge0" inPort="Port 0 (in)" metadata="Metadata1" outPort="Port 0 (out)" toNode="DATA_WRITER0:0"/>
80
+ </Phase>
81
+ <Phase number="1">
82
+ <Node enabled="enabled" fileURL="data/out.csv" guiHeight="77" guiName="CSV Writer" guiWidth="128" guiX="517" guiY="74" id="DATA_WRITER0" outputFieldNames="true" quotedStrings="true" type="DATA_WRITER"/>
83
+ </Phase>
84
+ </Graph>
data/lib/runtime.rb CHANGED
@@ -55,12 +55,15 @@ module GoodData
55
55
  end
56
56
  end
57
57
 
58
- def self.setup_clover_project(base)
58
+ def self.setup_clover_project(base, options={})
59
+
60
+ name = options[:name] || PARAMS[:project_name]
61
+
59
62
  [PROJECT_GRAPHS_ROOT, PROJECT_METADATA_ROOT, PROJECT_DATA_ROOT].each do |dir|
60
63
  FileUtils::mkdir_p base + dir
61
64
  end
62
65
  FileUtils::touch(base + 'params.txt')
63
- render_template("project.erb", PARAMS.merge(:project_name => "downloader-#{PARAMS[:project_name]}"), :to_file => base + '.project')
66
+ render_template("project.erb", PARAMS.merge(:project_name => name), :to_file => base + '.project')
64
67
  render_template("workspace.prm.erb", PARAMS, :to_file => base + 'workspace.prm')
65
68
  end
66
69
 
@@ -138,6 +141,11 @@ module GoodData
138
141
  pp report
139
142
  end
140
143
 
144
+ def self.sf_jack_in
145
+ client = get_sf_client(PARAMS)
146
+ binding.pry
147
+ end
148
+
141
149
  def self.generate_docs
142
150
  project = build_project
143
151
  sources = project.get_sources
@@ -209,7 +217,7 @@ module GoodData
209
217
  end
210
218
 
211
219
  def self.generate_downloaders(options={})
212
- setup_clover_project(CLOVER_DOWNLOADERS_ROOT)
220
+ setup_clover_project(CLOVER_DOWNLOADERS_ROOT, :name => "downloaders-#{PARAMS[:project_name]}")
213
221
  project = build_project
214
222
  sources = project.get_sources
215
223
  sf_sources = sources.find_all {|tap| tap[:source] == "salesforce" && tap[:incremental] == true}
@@ -226,16 +234,16 @@ module GoodData
226
234
 
227
235
  def self.execute_process(link, dir)
228
236
  result = GoodData.post(link, {
229
- :graphExecution => {
237
+ :execution => {
230
238
  :graph => "./#{dir}/graphs/main.grf",
231
239
  :params => {}
232
240
  }
233
241
  })
234
- GoodData.poll(result, "cloverExecutionTask")
242
+ GoodData.poll(result, "executionTask")
235
243
  end
236
244
 
237
- def self.connect_to_gd
238
- GoodData.logger = Logger.new(STDOUT)
245
+ def self.connect_to_gd(options={})
246
+ GoodData.logger = options[:logger]
239
247
  GoodData.connect(PARAMS[:gd_login], PARAMS[:gd_pass])
240
248
  GoodData.project = PARAMS[:project_pid] if !PARAMS[:project_pid].nil? && !PARAMS[:project_pid].empty?
241
249
  end
@@ -333,7 +341,7 @@ module GoodData
333
341
  process_id = options[:process]
334
342
 
335
343
  data = {
336
- :cloverTransformation => {
344
+ :process => {
337
345
  :name => deploy_name || "#{PARAMS[:project_name]}",
338
346
  :path => "/uploads/#{File.basename(temp.path)}"
339
347
  }
@@ -355,7 +363,7 @@ module GoodData
355
363
  res = deploy_graph(dir, options)
356
364
  block.call(res)
357
365
  ensure
358
- self_link = res["cloverTransformation"]["links"]["self"]
366
+ self_link = res["process"]["links"]["self"]
359
367
  GoodData.delete(self_link)
360
368
  end
361
369
  else
@@ -363,11 +371,16 @@ module GoodData
363
371
  end
364
372
  end
365
373
 
374
+ def self.generate_graph_template(name, target)
375
+ template_name = "#{name}_template.grf.erb"
376
+ render_template(template_name, PARAMS, :to_file => USER_DEFINED_GRAPHS_ROOT + target)
377
+ end
378
+
366
379
 
367
380
  def self.run(options)
368
381
 
369
382
  only_flow = options[:only]
370
- setup_clover_project(CLOVER_PROJECT_ROOT)
383
+ setup_clover_project(CLOVER_PROJECT_ROOT, :name => "etl-#{PARAMS[:project_name]}")
371
384
  p = build_project
372
385
  sources = p.get_sources
373
386
  datasets = p.get_datasets
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Graph author="fluke" created="Tue Feb 05 15:38:24 PST 2013" guiVersion="3.3.1" id="1360179808937" licenseType="Commercial" modified="Fri Feb 22 13:36:18 PST 2013" modifiedBy="fluke" name="process_name" revision="1.12" showComponentDetails="true">
3
+ <Global>
4
+ <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_in.xml" id="Metadata0"/>
5
+ <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_out.xml" id="Metadata1"/>
6
+ <MetadataGroup id="ComponentGroup0" name="metadata"/>
7
+ <Property fileURL="params.txt" id="GraphParameter0"/>
8
+ <Property fileURL="workspace.prm" id="GraphParameter1"/>
9
+ <Dictionary/>
10
+ </Global>
11
+ <Phase number="0">
12
+ <Node enabled="enabled" fileURL="data/1_in.csv" guiHeight="77" guiName="CSV Reader" guiWidth="128" guiX="124" guiY="169" id="DATA_READER0" quoteCharacter="&quot;" quotedStrings="true" skipRows="1" type="DATA_READER"/>
13
+ <Node enabled="enabled" fileURL="data/out.csv" guiHeight="77" guiName="CSV Writer" guiWidth="128" guiX="609" guiY="169" id="DATA_WRITER0" outputFieldNames="true" quoteCharacter="&quot;" quotedStrings="true" type="DATA_WRITER"/>
14
+ <Node enabled="enabled" guiHeight="65" guiName="Reformat" guiWidth="128" guiX="365" guiY="175" id="REFORMAT0" type="REFORMAT">
15
+ <attr name="transform"><![CDATA[//#CTL2
16
+
17
+ // Transforms input record into output record.
18
+ function integer transform() {
19
+ $out.0.* = $in.0.*;
20
+
21
+ return ALL;
22
+ }
23
+
24
+ // Called during component initialization.
25
+ // function boolean init() {}
26
+
27
+ // Called during each graph run before the transform is executed. May be used to allocate and initialize resources
28
+ // required by the transform. All resources allocated within this method should be released
29
+ // by the postExecute() method.
30
+ // function void preExecute() {}
31
+
32
+ // Called only if transform() throws an exception.
33
+ // function integer transformOnError(string errorMessage, string stackTrace) {}
34
+
35
+ // Called during each graph run after the entire transform was executed. Should be used to free any resources
36
+ // allocated within the preExecute() method.
37
+ // function void postExecute() {}
38
+
39
+ // Called to return a user-defined error message when an error occurs.
40
+ // function string getMessage() {}
41
+ ]]></attr>
42
+ </Node>
43
+ <Edge fromNode="DATA_READER0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge0" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (output)" toNode="REFORMAT0:0"/>
44
+ <Edge fromNode="REFORMAT0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge1" inPort="Port 0 (in)" metadata="Metadata1" outPort="Port 0 (out)" toNode="DATA_WRITER0:0"/>
45
+ </Phase>
46
+ </Graph>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gd_bam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-30 00:00:00.000000000 Z
12
+ date: 2013-05-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -258,7 +258,7 @@ dependencies:
258
258
  requirements:
259
259
  - - '='
260
260
  - !ruby/object:Gem::Version
261
- version: 0.5.10
261
+ version: 0.5.11
262
262
  type: :runtime
263
263
  prerelease: false
264
264
  version_requirements: !ruby/object:Gem::Requirement
@@ -266,7 +266,7 @@ dependencies:
266
266
  requirements:
267
267
  - - '='
268
268
  - !ruby/object:Gem::Version
269
- version: 0.5.10
269
+ version: 0.5.11
270
270
  - !ruby/object:Gem::Dependency
271
271
  name: highline
272
272
  requirement: !ruby/object:Gem::Requirement
@@ -350,6 +350,8 @@ files:
350
350
  - lib/graphs/process_activity.grf
351
351
  - lib/graphs/process_activity_dim.grf
352
352
  - lib/graphs/process_activity_owner.grf
353
+ - lib/graphs/process_forecast.grf
354
+ - lib/graphs/process_opp_records.grf
353
355
  - lib/graphs/process_opportunity.grf
354
356
  - lib/graphs/process_opportunity_line_item.grf
355
357
  - lib/graphs/process_opportunity_snapshot.grf
@@ -368,6 +370,7 @@ files:
368
370
  - templates/flow.rb.erb
369
371
  - templates/params.json.erb
370
372
  - templates/project.erb
373
+ - templates/reformat_template.grf.erb
371
374
  - templates/source.json.erb
372
375
  - templates/tap.json.erb
373
376
  - templates/update_dataset.script.erb
@@ -392,18 +395,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
392
395
  - - ! '>='
393
396
  - !ruby/object:Gem::Version
394
397
  version: '0'
395
- segments:
396
- - 0
397
- hash: 3491844236925090228
398
398
  required_rubygems_version: !ruby/object:Gem::Requirement
399
399
  none: false
400
400
  requirements:
401
401
  - - ! '>='
402
402
  - !ruby/object:Gem::Version
403
403
  version: '0'
404
- segments:
405
- - 0
406
- hash: 3491844236925090228
407
404
  requirements: []
408
405
  rubyforge_project:
409
406
  rubygems_version: 1.8.25