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.
- 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
|