iab-FinancialProductBuilder 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/lib/controllers/pbbase_controller.rb +155 -0
  2. data/lib/deriveDSL.rb +147 -0
  3. data/lib/genGITstructure.rb +31 -0
  4. data/lib/helpers/pb_helper.rb +352 -0
  5. data/lib/models.rb +129 -0
  6. data/lib/processmap.rb +84 -0
  7. data/lib/productconfig.rb +90 -0
  8. data/lib/templates_and_resources/DSLTemplates/layouts/CancelConfirm.oil +31 -0
  9. data/lib/templates_and_resources/DSLTemplates/layouts/ConfirmPayment.oil +32 -0
  10. data/lib/templates_and_resources/DSLTemplates/layouts/DeclineRefer.oil +32 -0
  11. data/lib/templates_and_resources/DSLTemplates/layouts/Errored.oil +32 -0
  12. data/lib/templates_and_resources/DSLTemplates/layouts/MTARiskDataUpdate.oil +44 -0
  13. data/lib/templates_and_resources/DSLTemplates/layouts/PolicySearch.oil +33 -0
  14. data/lib/templates_and_resources/DSLTemplates/layouts/ProductSelection.oil +48 -0
  15. data/lib/templates_and_resources/DSLTemplates/layouts/QNBRiskDataCollect.oil +44 -0
  16. data/lib/templates_and_resources/DSLTemplates/layouts/QuoteSearch.oil +36 -0
  17. data/lib/templates_and_resources/DSLTemplates/layouts/QuoteSummary.oil +40 -0
  18. data/lib/templates_and_resources/DSLTemplates/layouts/SaveConfirm.oil +33 -0
  19. data/lib/templates_and_resources/DSLTemplates/layouts/SearchResult.oil +34 -0
  20. data/lib/templates_and_resources/DSLTemplates/layouts/TakePayment.oil +42 -0
  21. data/lib/templates_and_resources/DSLTemplates/processes.oil +48 -0
  22. data/lib/templates_and_resources/DSLTemplates/product.oil +6 -0
  23. data/lib/templates_and_resources/DSLTemplates/rating.oil +5 -0
  24. data/lib/templates_and_resources/defaultBrand/damManifest.rb +63 -0
  25. data/lib/templates_and_resources/defaultBrand/images/2col[1].jpg +0 -0
  26. data/lib/templates_and_resources/defaultBrand/images/FirstCommercial.png +0 -0
  27. data/lib/templates_and_resources/defaultBrand/images/FirstCommercialBeta.png +0 -0
  28. data/lib/templates_and_resources/defaultBrand/images/FloristAdvert.jpg +0 -0
  29. data/lib/templates_and_resources/defaultBrand/images/bullet_star.png +0 -0
  30. data/lib/templates_and_resources/defaultBrand/images/help.png +0 -0
  31. data/lib/templates_and_resources/defaultBrand/images/hotel_teaser.jpg +0 -0
  32. data/lib/templates_and_resources/defaultBrand/images/india-flag.gif +0 -0
  33. data/lib/templates_and_resources/defaultBrand/images/information.png +0 -0
  34. data/lib/templates_and_resources/defaultBrand/images/lightbulb.png +0 -0
  35. data/lib/templates_and_resources/defaultBrand/images/pub_teaser.jpg +0 -0
  36. data/lib/templates_and_resources/defaultBrand/images/star.png +0 -0
  37. data/lib/templates_and_resources/defaultBrand/images/star_hollow.png +0 -0
  38. data/lib/templates_and_resources/defaultBrand/images/surgery_teaser.jpg +0 -0
  39. data/lib/templates_and_resources/defaultBrand/images/tick.png +0 -0
  40. data/lib/templates_and_resources/defaultBrand/images/uk-flag.png +0 -0
  41. data/lib/templates_and_resources/defaultBrand/images/van_teaser.jpg +0 -0
  42. data/lib/templates_and_resources/defaultBrand/teasers/_crossSellCommercialLines.erb +25 -0
  43. data/lib/templates_and_resources/defaultBrand/teasers/_crossSellPersonalLines.erb +43 -0
  44. data/lib/templates_and_resources/defaultBrand/teasers/_goodDealBetter.erb +28 -0
  45. data/lib/templates_and_resources/defaultBrand/teasers/beat_a.gif +0 -0
  46. data/lib/templates_and_resources/defaultBrand/teasers/beat_b.gif +0 -0
  47. data/lib/templates_and_resources/defaultBrand/teasers/beat_c.gif +0 -0
  48. data/lib/templates_and_resources/defaultBrand/teasers/car_icon_vsmall.gif +0 -0
  49. data/lib/templates_and_resources/defaultBrand/teasers/greyarrow.gif +0 -0
  50. data/lib/templates_and_resources/defaultBrand/teasers/home_icon_vsmall.gif +0 -0
  51. data/lib/templates_and_resources/defaultBrand/teasers/life_icon_vsmall.gif +0 -0
  52. data/lib/templates_and_resources/defaultBrand/teasers/splash_r_top.gif +0 -0
  53. data/lib/templates_and_resources/defaultBrand/teasers/travel_icon_vsmall.gif +0 -0
  54. data/lib/templates_and_resources/dictionaries/dictionary_en.rb +117 -0
  55. data/lib/templates_and_resources/layouts_and_grids/21.css +42 -0
  56. data/lib/templates_and_resources/layouts_and_grids/24.css +74 -0
  57. data/lib/templates_and_resources/layouts_and_grids/25.css +49 -0
  58. data/lib/templates_and_resources/layouts_and_grids/34.css +81 -0
  59. data/lib/templates_and_resources/layouts_and_grids/4.css +65 -0
  60. data/lib/templates_and_resources/layouts_and_grids/5.css +64 -0
  61. data/lib/templates_and_resources/layouts_and_grids/LayoutGala07.css +25 -0
  62. data/lib/templates_and_resources/lists/PersonTitles_en.rb +9 -0
  63. metadata +145 -0
@@ -0,0 +1,155 @@
1
+ # Copyright (c) 2007-2009 Orangery Technology Limited
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ require 'Marshaller'
5
+ require 'helpers/pb_helper'
6
+
7
+ class PbBaseController < ApplicationController
8
+
9
+ include Marshaller
10
+ include PbHelper
11
+
12
+ def products
13
+ product = params['product']
14
+ if (product != nil) then
15
+ if (!product?(product)) then
16
+ session[:selected_product] = nil
17
+ session[:selected_product_item] = nil
18
+ else
19
+ session[:selected_product] = product
20
+ session[:selected_product_item] = nil
21
+ end
22
+ end
23
+ entity = params['entity']
24
+ if (entity != nil) then
25
+ session[:selected_product_item] = entity
26
+ end
27
+ render(:template => "pb/products", :layout => 'products')
28
+ end
29
+
30
+ def product_add
31
+ name = params['name']
32
+ unless (name == nil) then
33
+ name.strip!()
34
+ name.capitalize!()
35
+ addProduct(name)
36
+ session[:selected_product] = name
37
+ session[:selected_product_item] = nil
38
+ end
39
+ redirect_to(:action => 'products')
40
+ end
41
+
42
+ def product_clone
43
+ existingName = session[:selected_product]
44
+ clonedName = params['clonedName']
45
+ unless ((existingName == nil) || (clonedName == nil) || (clonedName.empty?())) then
46
+ clonedName.strip!()
47
+ clonedName = Inflector.camelize(clonedName)
48
+ cloneProduct(existingName, clonedName)
49
+ session[:selected_product] = clonedName
50
+ session[:selected_product_item] = nil
51
+ end
52
+ redirect_to(:action => 'products')
53
+ end
54
+
55
+ def product_delete
56
+ name = session[:selected_product]
57
+ unless (name == nil) then
58
+ deleteProduct(name)
59
+ session[:selected_product] = nil
60
+ session[:selected_product_item] = nil
61
+ end
62
+ redirect_to(:action => 'products')
63
+ end
64
+
65
+ def entity_add
66
+ name = params['name']
67
+ if (params['type'] == 'coverage') then
68
+ type = :coverage
69
+ else
70
+ type = :entity
71
+ end
72
+ unless (name == nil) then
73
+ addProductEntity(session[:selected_product], type, name)
74
+ end
75
+ render(:text => :OK)
76
+ end
77
+
78
+ def update_cardinality
79
+ entity = params['entity']
80
+ cardinality = params['cardinality']
81
+ unless ((entity == nil) || (cardinality == nil)) then
82
+ updateEntityCardinality(session[:selected_product], entity, cardinality)
83
+ end
84
+ render(:text => :OK)
85
+ end
86
+
87
+ def entity_delete
88
+ name = params['name']
89
+ unless (name == nil) then
90
+ deleteProductEntity(session[:selected_product], name)
91
+ if (session[:selected_product_item] == name) then
92
+ session[:selected_product_item] = nil
93
+ end
94
+ end
95
+ render(:text => :OK)
96
+ end
97
+
98
+ def entity_save
99
+ entities = params['entities']
100
+ unless (entities == nil) then
101
+ selected = entities.split(' ');
102
+ saveEntityDetails(session[:selected_product], session[:selected_product_item], selected.sort)
103
+ end
104
+ render(:text => :OK)
105
+ end
106
+
107
+ def dictionary_update
108
+ lang = session[:lang]
109
+ id = params['id']
110
+ value = params['value']
111
+ if ((lang != nil) && (id != nil)) then
112
+ updateDictionary(lang, id, value)
113
+ end
114
+ # render back the value to confirm change
115
+ render(:text => value)
116
+ end
117
+
118
+ def test_drive
119
+ # extract data from incoming params
120
+ lang = params['lang']
121
+ brand = params['brand']
122
+ product = params['product']
123
+ # the following config could be externalised if required
124
+ port = '9000'
125
+ edit = 'true'
126
+ environment = 'development'
127
+ logDir = 'log'
128
+ pidFile = File.join(logDir, 'testdrive.pid')
129
+ logFile = File.join(logDir, 'testdrive.log')
130
+ if (File.exist?(logFile)) then
131
+ FileUtils.rm(logFile)
132
+ end
133
+ # stop existing mongrel if there is one
134
+ startCmd = "source ~/.bash_profile;mongrel_rails start --daemonize --port #{port} --environment #{environment} --log #{logFile} --pid #{pidFile}"
135
+ stopCmd = "mongrel_rails stop --pid #{pidFile}"
136
+ restartCmd = "mongrel_rails restart --pid #{pidFile}"
137
+ if (File.exist?(pidFile)) then
138
+ cmd = restartCmd
139
+ else
140
+ cmd = startCmd
141
+ end
142
+ system(cmd)
143
+ sleep(1)
144
+ puts "Executed Mongrel command [#{cmd}] see log file [#{logFile}] for further details\n"
145
+ # send back the url for test driving
146
+ url = "http://127.0.0.1:#{port}/iab/QNBRiskDataCollect?brand=#{brand}&product=#{product}&lang=#{lang}&edit=#{edit}"
147
+ puts "Returned URL for test drive [#{url}]"
148
+ render(:text => url)
149
+ end
150
+
151
+ def update_mandatory
152
+ puts 'PLEASE WRITE ME'
153
+ render(:text => :OK)
154
+ end
155
+ end
data/lib/deriveDSL.rb ADDED
@@ -0,0 +1,147 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # == Copyright
4
+ #
5
+ # Copyright (c) 2007-2009 Orangery Technology Limited
6
+ # Licensed under the same terms as Ruby.
7
+ #
8
+ # == Synopsis
9
+ #
10
+ # A script to call high level DSL interpreters and create an IAB compliant
11
+ # repository of product level DSL from an enterprise data and process DSL model
12
+ # of the business.
13
+ #
14
+ # In short this offers an easy way to quickly bootsrap an insurance business
15
+ # by defining products, their data models and their processes.
16
+ #
17
+ # == Usage
18
+ #
19
+ # ./deriveDSL.rb 'input path' 'output path' OrgName DataModel.oil SiteProcess.oil
20
+ #
21
+
22
+ require 'rubygems'
23
+ require 'DataModelInterpreter'
24
+ require 'SiteProcessInterpreter'
25
+ require 'Element'
26
+
27
+ require 'models'
28
+ require 'processmap'
29
+ require 'productconfig'
30
+
31
+ require 'genGITstructure'
32
+ require 'rdoc/usage'
33
+
34
+ if (ARGV.length != 5)
35
+ RDoc::usage
36
+ end
37
+
38
+ INPUT = ARGV[0]
39
+ OUTPUT = ARGV[1]
40
+ ORG = ARGV[2]
41
+ DM = ARGV[3]
42
+ SP = ARGV[4]
43
+
44
+ contents = ""
45
+ open("#{INPUT}/#{SP}") {|f| contents = f.read }
46
+ hoo = SiteProcessInterpreter.execute(contents.to_s) #hoo is an array of objects
47
+ # the array contains three child objects:-
48
+ # 0) distinct list of steps with associated navigation points, a "do" statement (if any) (a hash)
49
+ # 1) distinct list of products (an array)
50
+ # 2) distinct list of data items (a set)
51
+
52
+ tree = GenGITStructure.new
53
+ tree.makeDirTree(OUTPUT,ORG,hoo[1])
54
+
55
+ open("#{INPUT}/#{DM}") {|f| @contents = f.read }
56
+ dsl = @contents.to_s
57
+ elements = DataModelInterpreter.execute(dsl) #elements is an array of 'Element' objects
58
+
59
+ # Element structure is:-
60
+ # isacoverage? - indicates whether top level - really should be named 'top level coverage or entity?'
61
+ # name - name
62
+ # children - array elements
63
+ # parent - an element
64
+ # fields - name, type, mask
65
+ # type - coverage or entity
66
+
67
+ modelData = Models.new
68
+ resultDMFiles = modelData.generateFiles(elements)
69
+ dictionaryEntries = modelData.genDict(elements)
70
+
71
+ # create 'the library'
72
+ # these are coverage and entity definitions in a RAILS format
73
+ # exactly the same format as RAILS would generate from a relational schema
74
+ # in .../libraries/coverages
75
+ # in .../libraries/entities
76
+ resultDMFiles.each do |k,v|
77
+ File.open(File.join(OUTPUT, ORG,'git','libraries',"#{v[3]}","#{k}DataModel.rb"), 'w') {|f| f.write(v[0]) }
78
+ File.open(File.join(OUTPUT, ORG,'git','libraries',"#{v[3]}","#{k}NodeName.rb"), 'w') {|f| f.write(v[1]) }
79
+ File.open(File.join(OUTPUT, ORG,'git','libraries',"#{v[3]}","#{k}PropertyHash"), 'w') {|f| f.write(v[2]) }
80
+ end
81
+
82
+ # create the product process DSL file - git/products/PRODUCT/DSL/processes.oil
83
+ # use hoo[0] to drive this
84
+ pmap = ProcessMap.new
85
+ map = pmap.generateMap(hoo[0])
86
+ File.open(File.join(OUTPUT, ORG,'git','products',"#{hoo[1]}",'DSL','processes.oil'), 'w') {|f| f.write(map) }
87
+
88
+ # create layouts for each of the steps of each process
89
+ # generate to git/products/PRODUCT/DSL/layouts
90
+ # drive this from hoo[0] data since this contains steps and data usage info
91
+ layouts = pmap.genLayouts(hoo[0],elements)
92
+ layouts.each do |l|
93
+ File.open(File.join(OUTPUT, ORG,'git','products',"#{hoo[1]}",'DSL','layouts',"#{l[0]}.oil"), 'w') {|f| f.write(l[1]) }
94
+ end
95
+
96
+ # create product level manifest of coverages and entities - git/products/PRODUCT/DSL/product.oil
97
+ # for now use hoo[2] to drive this
98
+ pcfg = ProductConfig.new
99
+ cfg = pcfg.createManifest(hoo[1],elements)
100
+ File.open(File.join(OUTPUT, ORG,'git','products',"#{hoo[1]}",'DSL','product.oil'), 'w') {|f| f.write(cfg) }
101
+
102
+ # create product level entities and coverages field usage files...essentially 'views' on the coverage record
103
+ # generate to git/products/PRODUCT/DSL/coverages (or /entities)
104
+ # use hoo[2] and field info from the elements object returned from DataModelInterpreter
105
+ entcov = pcfg.genViews(elements)
106
+ entcov[0].each do |fd|
107
+ File.open(File.join(OUTPUT, ORG,'git','products',"#{hoo[1]}",'DSL','coverages',"#{fd[0]}.oil"), 'w') {|f| f.write(fd[1]) }
108
+ end
109
+ entcov[1].each do |fd|
110
+ File.open(File.join(OUTPUT, ORG,'git','products',"#{hoo[1]}",'DSL','entities',"#{fd[0]}.oil"), 'w') {|f| f.write(fd[1]) }
111
+ end
112
+
113
+ # create git/products/PRODUCT/DSL/rating.oil file by simply writing out 2 hardcoded lines for the moment
114
+ rating = ""
115
+ rating << "dictionary 'XML','ShopPackageQuoteNBRq','110','100','ShopSkel100-01'\n"
116
+ rating << "rating_engine 'RTE','Response'"
117
+ File.open(File.join(OUTPUT, ORG,'git','products',"#{hoo[1]}",'DSL','rating.oil'), 'w') {|f| f.write(rating) }
118
+
119
+
120
+ # copy layout grids from lib/templates_and_resources/layouts_and_grids
121
+ # to git/libraries/genericlayoutgrids
122
+ pcfg.copyDirectoryWithoutHiddenRecursively(File.join('templates_and_resources','layouts_and_grids'),File.join(OUTPUT, ORG,'git','libraries','genericlayoutgrids','stylesheets'))
123
+
124
+ # copy lib/templates_and_resources/defaultBrand contents
125
+ # to git/brands/default
126
+ pcfg.copyDirectoryWithoutHiddenRecursively(File.join('templates_and_resources','defaultBrand'),File.join(OUTPUT, ORG,'git','brands','Default'))
127
+
128
+ pcfg.copyDirectoryWithoutHiddenRecursively(File.join('templates_and_resources','DSLTemplates'),File.join(OUTPUT, ORG,'git','libraries','DSLTemplates'))
129
+
130
+ # create dictionary file and place in git/products
131
+ # take dictionary template from lib/templates_and_resources/dictionary_en.rb
132
+ # and splice in data model specific strings by replacing string #ENTITYSPECIFIC
133
+ # use xpath to derive string name and use node name as the translation target
134
+ pcfg.copyDirectoryWithoutHiddenRecursively(File.join('templates_and_resources','dictionaries'),File.join(OUTPUT, ORG,'git','products'))
135
+ open(File.join(OUTPUT, ORG,'git','products','dictionary_en.rb'), 'r+') do |f|
136
+ content = f.read()
137
+ content.gsub!('#ENTITYSPECIFIC',dictionaryEntries)
138
+ f.truncate(0)
139
+ f.rewind()
140
+ f.write(content)
141
+ f.close()
142
+ end
143
+
144
+ # copy example list file into git/libraries/lists from lib/templates_and_resources/lists/PersonTitles_en.rb
145
+ # to git/libraries/lists/PersonTitles_en.rb
146
+ pcfg.copyDirectoryWithoutHiddenRecursively(File.join('templates_and_resources','lists'),File.join(OUTPUT, ORG,'git','libraries','lists'))
147
+
@@ -0,0 +1,31 @@
1
+ require 'fileutils'
2
+
3
+ include FileUtils
4
+
5
+ class GenGITStructure
6
+ def makeDirTree(*args)
7
+ output = args[0]
8
+ org = args[1]
9
+ productNames = args[2]
10
+
11
+ dir = ""
12
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org))
13
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git'))
14
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','brands'))
15
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','libraries'))
16
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','libraries','coverages'))
17
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','libraries','entities'))
18
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','libraries','genericlayoutgrids'))
19
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','libraries','genericlayoutgrids','stylesheets'))
20
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','libraries','lists'))
21
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','products'))
22
+
23
+ productNames.each do |p|
24
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','products',"#{p}"))
25
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','products',"#{p}",'DSL'))
26
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','products',"#{p}",'DSL','coverages'))
27
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','products',"#{p}",'DSL','entities'))
28
+ Dir.mkdir(dir) if !File.exist?(dir = File.join(output, org,'git','products',"#{p}",'DSL','layouts'))
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,352 @@
1
+ # Copyright (c) 2007-2009 Orangery Technology Limited
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ require 'fileutils'
5
+ require 'ProductInterpreter'
6
+ require 'CoverageInterpreter2'
7
+ require 'ProductInterpreter2'
8
+ require 'channel_manager'
9
+
10
+ module PbHelper
11
+
12
+ include FileUtils
13
+ include ChannelManager
14
+
15
+ def product?(name)
16
+ if ((name != nil) && (!name.empty?()) && File.directory?(File.join(PRODUCTS_ROOT, name))) then
17
+ # TODO: add code here to perform a validation of the product
18
+ # Possible steps:
19
+ # 1. Check there is a product.oil
20
+ # 2. Check that each entity and coverage in product.oil has a valid entity/coverage oil file
21
+ # 3. Ensure all items are in the library etc.
22
+ # .... loads of other stuff
23
+ return true
24
+ end
25
+ return false
26
+ end
27
+
28
+ def getProducts
29
+ products = Array.new
30
+ Dir.glob(File.join(PRODUCTS_ROOT, '*'), File::FNM_PATHNAME) do |p|
31
+ if File.directory?(p)
32
+ products.push(File.basename(p))
33
+ end
34
+ end
35
+ products.sort
36
+ end
37
+
38
+ def getLanguages
39
+ languages = Array.new
40
+ Dir.glob(File.join(PRODUCTS_ROOT, 'dictionary_*.rb'), File::FNM_PATHNAME) do |p|
41
+ languages.push(File.basename(p).sub(/dictionary_(.\w+)\.rb/, '\1'))
42
+ end
43
+ languages.sort
44
+ end
45
+
46
+ def getBrands
47
+ brands = Array.new
48
+ Dir.glob(File.join(BRANDS_ROOT, '*'), File::FNM_PATHNAME) do |p|
49
+ if File.directory?(p)
50
+ brands.push(File.basename(p))
51
+ end
52
+ end
53
+ brands.sort
54
+ end
55
+
56
+ def addProduct(name)
57
+ productDirectory = File.join(PRODUCTS_ROOT, name)
58
+ # create the new product directory
59
+ Dir.mkdir(productDirectory)
60
+ # create the DSL folder
61
+ productDSLDirectory = File.join(productDirectory, 'DSL')
62
+ Dir.mkdir(productDSLDirectory)
63
+ # copy the DSL template directory
64
+ copyDirectoryWithoutHiddenRecursively(PRODUCT_DSL_TEMPLATE_ROOT, productDSLDirectory)
65
+ # update product.oil to put in the produt name
66
+ findAndReplaceInFile(File.join(productDirectory, 'DSL', 'product.oil'), /#\$PRODUCT_NAME\$/, name)
67
+ end
68
+
69
+ def cloneProduct(existingProductName, newProductName)
70
+ existingProductDirectory = File.join(PRODUCTS_ROOT, existingProductName)
71
+ newProductDirectory = File.join(PRODUCTS_ROOT, newProductName)
72
+ # copy the product in its entirety
73
+ copyDirectoryWithoutHiddenRecursively(existingProductDirectory, newProductDirectory)
74
+ # update the main oil files
75
+ findAndReplaceInFile(File.join(newProductDirectory, 'DSL', 'product.oil'), /(\s+:)#{existingProductName}/, "\\1#{newProductName}")
76
+ end
77
+
78
+ def deleteProduct(name)
79
+ FileUtils.mv(File.join(PRODUCTS_ROOT, name), File.join(PRODUCTS_ROOT, '.' + name))
80
+ end
81
+
82
+ def getProductEntities(product, type)
83
+ open(File.join(PRODUCTS_ROOT, product, 'DSL','product.oil')) do |f|
84
+ product = ProductInterpreter2.execute(f.read())
85
+ f.close()
86
+ end
87
+ product.method(type).call().sort()
88
+ end
89
+
90
+ def addProductEntity(product, type, name)
91
+ # add the coverage to product.oil
92
+ # and ...
93
+ # create the new coverage oil file
94
+ if (type == :coverage) then
95
+ findAndReplaceInFile(File.join(PRODUCTS_ROOT, product, 'DSL', 'product.oil'), /(\s+endcoverages)/, "\n has_one :#{name}\\1")
96
+ f = File.new(File.join(PRODUCTS_ROOT, product, 'DSL', 'coverages', name + '.oil'), 'w+')
97
+ regex = /(\s+#\$COVERAGES\$)/
98
+ else
99
+ findAndReplaceInFile(File.join(PRODUCTS_ROOT, product, 'DSL', 'product.oil'), /(\s+endentities)/, "\n has_one :#{name}\\1")
100
+ f = File.new(File.join(PRODUCTS_ROOT, product, 'DSL', 'entities', name + '.oil'), 'w+')
101
+ regex = /(\s+#\$ENTITIES\$)/
102
+ end
103
+ # some coverages and entities are essential, lets find them now
104
+ recommendedSelections = getDefaultSelections(name, type, nil, nil)
105
+ f.chmod(0644)
106
+ oil = <<OIL
107
+ #{type} :#{name}
108
+ #{recommendedSelections}
109
+ end#{type}
110
+ OIL
111
+ f.write(oil);
112
+ f.close()
113
+ # scan the layout oils and add this entity/coverage if required in the markup
114
+ Dir.glob(File.join(PRODUCTS_ROOT, product, 'DSL', 'layouts', '*.oil')) do |lf|
115
+ findAndReplaceInFile(lf, regex, "\n #{type} :#{name}\\1")
116
+ end
117
+ end
118
+
119
+ def getDefaultSelections(entity, type, recommendedSelections, path)
120
+ if (recommendedSelections == nil) then
121
+ recommendedSelections = ''
122
+ loadLibraryEntity(entity, type)
123
+ @hash = getPropertyHash(type, entity)
124
+ path = Array.new
125
+ path.push(entity)
126
+ else
127
+ path.push(entity.sub(/#{path.join()}/, ''))
128
+ end
129
+ c = eval(entity)
130
+ associations = c.reflect_on_all_associations()
131
+ associations.each do |a|
132
+ className = a.name.id2name
133
+ klass = eval(className)
134
+ # see if this entity is defined as essential in the property hash
135
+ sectionName = "#{className}MD"
136
+ section = @hash[sectionName]
137
+ if (section != nil) then
138
+ value = @hash[sectionName]['usebydefault']
139
+ end
140
+ # puts "Entity [#{className}] value [#{value}]\n"
141
+ if (value == 'true') then
142
+ recommendedSelections << ' use '
143
+ path.push(klass.nodeName)
144
+ path.each do |t|
145
+ unless t == path.first
146
+ recommendedSelections << ':'
147
+ recommendedSelections << t
148
+ unless (t.object_id() == path.last.object_id())
149
+ recommendedSelections << ','
150
+ end
151
+ end
152
+ end
153
+ path.pop()
154
+ recommendedSelections << "\n"
155
+ end
156
+ getDefaultSelections(className, type, recommendedSelections, path)
157
+ path.pop()
158
+ end unless (associations.empty?())
159
+ recommendedSelections
160
+ end
161
+
162
+ def deleteProductEntity(product, entity)
163
+ # remove the entry from product.oil
164
+ productOilFile = File.join(PRODUCTS_ROOT, product, 'DSL', 'product.oil')
165
+ cardinalityMatch = '((' + getCardinalities().join(')|(') + '))'
166
+ findAndReplaceInFile(productOilFile, /^\s*#{cardinalityMatch}\s*:\s*#{entity}\s*\n/, '')
167
+ # delete the specific oil file
168
+ fileName = File.join(PRODUCTS_ROOT, product, 'DSL', 'coverages', "#{entity}.oil")
169
+ unless (File.exists?(fileName)) then
170
+ fileName = File.join(PRODUCTS_ROOT, product, 'DSL', 'entities', "#{entity}.oil")
171
+ end
172
+ FileUtils.rm(fileName, :force => true)
173
+ # remove references from layout files
174
+ Dir.glob(File.join(PRODUCTS_ROOT, product, 'DSL', 'layouts', '*.oil'), File::FNM_PATHNAME) do |c|
175
+ # NOTE: entities and coverages can obviously have instructions bounded in {} after them
176
+ # e.g. title, hide etc.etc. so we need to make sure our search is fuzzy enough
177
+ # At this stage I have elected to just look for :Entity in any line and kill the line
178
+ findAndReplaceInFile(c, /^.*?:#{entity}.*?\n/, '')
179
+ end
180
+ end
181
+
182
+ def updateEntityCardinality(product, entity, cardinality)
183
+ fileName = File.join(PRODUCTS_ROOT, product, 'DSL', 'product.oil')
184
+ findAndReplaceInFile(fileName, /(^\s+)[^\s]+(\s*:#{entity})/, "\\1#{cardinality}\\2")
185
+ end
186
+
187
+ def saveEntityDetails(product, entity, selections)
188
+ # assert type as coverage and if the file doesn't exist assume entity
189
+ type = :coverage
190
+ fileName = File.join(PRODUCTS_ROOT, product, 'DSL', 'coverages', "#{entity}.oil")
191
+ unless (File.exists?(fileName)) then
192
+ type = :entity
193
+ fileName = File.join(PRODUCTS_ROOT, product, 'DSL', 'entities', "#{entity}.oil")
194
+ end
195
+ open(fileName, 'w') do |f|
196
+ f << "#{type} :" << entity << "\n"
197
+ selections.each do |s|
198
+ f << ' use ' << s << "\n"
199
+ end
200
+ f << "end#{type}"
201
+ f.close()
202
+ end
203
+ end
204
+
205
+ def getLibraryEntities(type)
206
+ if (type == :coverage) then
207
+ root = COVERAGE_DEF_ROOT
208
+ else
209
+ root = ENTITY_DEF_ROOT
210
+ end
211
+ entities = Array.new
212
+ Dir.glob(File.join(root, '*PropertyHash'), File::FNM_PATHNAME) do |c|
213
+ entities.push(File.basename(c.to_s).gsub(/(.*)PropertyHash/, '\1'))
214
+ end
215
+ entities.sort
216
+ end
217
+
218
+ def getEntityDetails(product, entity)
219
+ # find the definition of this coverage in this product, could be entity or coverage
220
+ fileName = File.join(PRODUCTS_ROOT, product, 'DSL', 'coverages', "#{entity}.oil")
221
+ type = :coverage
222
+ unless (File.exists?(fileName)) then
223
+ fileName = File.join(PRODUCTS_ROOT, product, 'DSL', 'entities', "#{entity}.oil")
224
+ type = :entity
225
+ end
226
+ # get the library definition of the coverage
227
+ lcd = walkLibraryEntity(entity, type, nil)
228
+ # go through all the items in the oil file that have been used and "check" them
229
+ open(fileName) do |f|
230
+ CoverageInterpreter2.execute(f.read).each do |s|
231
+ lcd = lcd.gsub(/(\sname=\"#{s}\")/, '\1 checked="checked"')
232
+ end
233
+ end
234
+ # puts lcd
235
+ lcd
236
+ end
237
+
238
+ def getCardinalities()
239
+ cardinalities = ['has_one', 'has_many']
240
+ cardinalities
241
+ end
242
+
243
+ def updateDictionary(lang, key, value)
244
+ open(File.join(PRODUCTS_ROOT, "dictionary_#{lang}.rb"), 'r+') do |f|
245
+ content = f.read()
246
+ # is the string already in the dictionary?
247
+ if (content.match(/^\s+\"#{key}\"\s+=>\s+\"[^\"]*\"\s*,/) != nil) then
248
+ puts "Updating dictionary: Language[#{lang}] key [#{key}] value [#{value}]\n"
249
+ content.gsub!(/(^\s+\"#{key}\"\s+=>\s+\")[^\"]*(\"\s*,)/, "\\1#{value}\\2")
250
+ else
251
+ puts "Adding to dictionary: Language[#{lang}] key [#{key}] value [#{value}]\n"
252
+ newEntry = "\n \"#{key}\" => \"#{value}\","
253
+ # add the new lookup at the start of the dictionary
254
+ content.gsub!(/(^\s*def\s+dictionary\s*\n\s*\{)/, "\\1#{newEntry}")
255
+ end
256
+ f.truncate(0)
257
+ f.rewind()
258
+ f.write(content)
259
+ f.close()
260
+
261
+ end
262
+ end
263
+
264
+ def walkLibraryEntity(entity, type, path)
265
+ introduce_dictionary(PRODUCTS_ROOT, 'en')
266
+ if (path == nil) then
267
+ loadLibraryEntity(entity, type)
268
+ path = Array.new
269
+ path.push(entity)
270
+ else
271
+ path.push(entity.sub(/#{path.join()}/, ''))
272
+ end
273
+ result = ''
274
+ associations = eval(entity).reflect_on_all_associations()
275
+ #don't render markup if there's nothing there
276
+ unless(associations.empty?) then
277
+ result << '<ul>' << "\n"
278
+ associations.each do |a|
279
+ className = a.name.id2name
280
+ result << '<li>' << '<input type="checkbox" name="'
281
+ nodeName = eval(className).nodeName
282
+ path.push(nodeName)
283
+ path.each do |t|
284
+ unless t == path.first
285
+ result << ':' << t
286
+ unless (t.object_id() == path.last.object_id())
287
+ result << ','
288
+ end
289
+ end
290
+ end
291
+ path.pop()
292
+ result << '"/>' << '<a>' << nodeName << '</a>'
293
+ # try and do a lookup on the dictionary
294
+ dictionaryKey = (entity + '_' + nodeName).downcase()
295
+ dictionaryTranslation = __(dictionaryKey)
296
+ if (dictionaryTranslation != dictionaryKey) then
297
+ result << '<p><small><i>' << dictionaryTranslation << '</i></small></p>'
298
+ end
299
+ result << walkLibraryEntity(className, type, path) << '</li>'
300
+ path.pop()
301
+ end
302
+ result << '</ul>'
303
+ end
304
+ result
305
+ end
306
+
307
+ def copyDirectoryWithoutHiddenRecursively(src, dest)
308
+ # make the destination directory if it does not exist
309
+ unless (File.directory?(dest)) then
310
+ FileUtils.mkpath(dest)
311
+ end
312
+ # recursively copy files and folders without hidden files
313
+ Dir.glob(File.join(src, '*'), File::FNM_PATHNAME) do |p|
314
+ if (File.directory?(p))
315
+ copyDirectoryWithoutHiddenRecursively(p, File.join(dest, File.basename(p)))
316
+ else
317
+ FileUtils.cp(p, dest)
318
+ end
319
+ end
320
+ end
321
+
322
+ def loadLibraryEntity(entity, type)
323
+ # now its time to dynamically load the the entity and its children from the library
324
+ if (type == :coverage) then
325
+ libraryPath = COVERAGE_DEF_ROOT
326
+ else
327
+ libraryPath = ENTITY_DEF_ROOT
328
+ end
329
+ require(File.join(libraryPath, entity + 'EntityModel.rb'))
330
+ require(File.join(libraryPath, entity + 'NodeName.rb'))
331
+ end
332
+
333
+ def getPropertyHash(type, entity)
334
+ if (type == :coverage) then
335
+ libraryPath = COVERAGE_DEF_ROOT
336
+ else
337
+ libraryPath = ENTITY_DEF_ROOT
338
+ end
339
+ return YAML::load(open(File.join(libraryPath, entity + 'PropertyHash'), 'r'))
340
+ end
341
+
342
+ def findAndReplaceInFile(fileName, findExpression, replaceExpression)
343
+ open(fileName, 'r+') do |f|
344
+ content = f.read()
345
+ content.gsub!(findExpression, replaceExpression)
346
+ f.truncate(0)
347
+ f.rewind()
348
+ f.write(content)
349
+ f.close()
350
+ end
351
+ end
352
+ end