iab-FinancialProductBuilder 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/controllers/pbbase_controller.rb +155 -0
- data/lib/deriveDSL.rb +147 -0
- data/lib/genGITstructure.rb +31 -0
- data/lib/helpers/pb_helper.rb +352 -0
- data/lib/models.rb +129 -0
- data/lib/processmap.rb +84 -0
- data/lib/productconfig.rb +90 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/CancelConfirm.oil +31 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/ConfirmPayment.oil +32 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/DeclineRefer.oil +32 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/Errored.oil +32 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/MTARiskDataUpdate.oil +44 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/PolicySearch.oil +33 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/ProductSelection.oil +48 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/QNBRiskDataCollect.oil +44 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/QuoteSearch.oil +36 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/QuoteSummary.oil +40 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/SaveConfirm.oil +33 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/SearchResult.oil +34 -0
- data/lib/templates_and_resources/DSLTemplates/layouts/TakePayment.oil +42 -0
- data/lib/templates_and_resources/DSLTemplates/processes.oil +48 -0
- data/lib/templates_and_resources/DSLTemplates/product.oil +6 -0
- data/lib/templates_and_resources/DSLTemplates/rating.oil +5 -0
- data/lib/templates_and_resources/defaultBrand/damManifest.rb +63 -0
- data/lib/templates_and_resources/defaultBrand/images/2col[1].jpg +0 -0
- data/lib/templates_and_resources/defaultBrand/images/FirstCommercial.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/FirstCommercialBeta.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/FloristAdvert.jpg +0 -0
- data/lib/templates_and_resources/defaultBrand/images/bullet_star.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/help.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/hotel_teaser.jpg +0 -0
- data/lib/templates_and_resources/defaultBrand/images/india-flag.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/images/information.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/lightbulb.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/pub_teaser.jpg +0 -0
- data/lib/templates_and_resources/defaultBrand/images/star.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/star_hollow.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/surgery_teaser.jpg +0 -0
- data/lib/templates_and_resources/defaultBrand/images/tick.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/uk-flag.png +0 -0
- data/lib/templates_and_resources/defaultBrand/images/van_teaser.jpg +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/_crossSellCommercialLines.erb +25 -0
- data/lib/templates_and_resources/defaultBrand/teasers/_crossSellPersonalLines.erb +43 -0
- data/lib/templates_and_resources/defaultBrand/teasers/_goodDealBetter.erb +28 -0
- data/lib/templates_and_resources/defaultBrand/teasers/beat_a.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/beat_b.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/beat_c.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/car_icon_vsmall.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/greyarrow.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/home_icon_vsmall.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/life_icon_vsmall.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/splash_r_top.gif +0 -0
- data/lib/templates_and_resources/defaultBrand/teasers/travel_icon_vsmall.gif +0 -0
- data/lib/templates_and_resources/dictionaries/dictionary_en.rb +117 -0
- data/lib/templates_and_resources/layouts_and_grids/21.css +42 -0
- data/lib/templates_and_resources/layouts_and_grids/24.css +74 -0
- data/lib/templates_and_resources/layouts_and_grids/25.css +49 -0
- data/lib/templates_and_resources/layouts_and_grids/34.css +81 -0
- data/lib/templates_and_resources/layouts_and_grids/4.css +65 -0
- data/lib/templates_and_resources/layouts_and_grids/5.css +64 -0
- data/lib/templates_and_resources/layouts_and_grids/LayoutGala07.css +25 -0
- data/lib/templates_and_resources/lists/PersonTitles_en.rb +9 -0
- 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
|