iab-FinancialProductBuilder 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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