concrete 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -30,3 +30,10 @@
30
30
  * Fixed marker (cursor) positioning for editor nodes with offset
31
31
  * Fixed exception in case fold control nodes are not present
32
32
 
33
+ =0.2.1 (September 21st, 2010)
34
+
35
+ * Added support for HAML style HTML templates and stylesheets based on SASS
36
+ * Fixed layout/positioning problems when a doctype is provided (added missing 'px' unit)
37
+ * Fixed bug not allowing to finish editing of a text attribute if an integer attribute has been edited before
38
+ * Fixed bug not allowing to position the cursor with the mouse in a text field in edit mode
39
+
@@ -134,12 +134,14 @@ Concrete.Editor = Class.create({
134
134
  this._handleInfoPopups(event);
135
135
  }
136
136
  this._handleRefHighlight(event);
137
- this.popup.setStyle({left: event.clientX+20, top: event.clientY+20});
137
+ this.popup.setStyle({left: event.clientX+20+'px', top: event.clientY+20+'px'});
138
138
  }
139
139
  if (this.inlineEditor.isActive) {
140
140
  if (event.type == "click" && event.isLeftClick()) {
141
- this.inlineEditor.cancel()
142
- this.selector.selectDirect(Event.element(event));
141
+ if (!Event.element(event).up().hasClassName("ct_inline_editor")) {
142
+ this.inlineEditor.cancel();
143
+ this.selector.selectDirect(Event.element(event));
144
+ }
143
145
  }
144
146
  else if (event.keyCode == 9) { // tab
145
147
  this.inlineEditor.finish();
@@ -512,7 +514,7 @@ Concrete.Editor = Class.create({
512
514
  adjustMarker: function() {
513
515
  var cur = this.selector.getCursorPosition();
514
516
  var poff = this.marker.getOffsetParent().cumulativeOffset();
515
- this.marker.setStyle({left: cur.x-poff.left, top: cur.y-poff.top});
517
+ this.marker.setStyle({left: cur.x-poff.left+'px', top: cur.y-poff.top+'px'});
516
518
  },
517
519
 
518
520
  getModel: function() {
@@ -11,43 +11,44 @@ Concrete.InlineEditor = Class.create(Concrete.BasicInlineEditor, {
11
11
  },
12
12
 
13
13
  edit: function(element, opt) {
14
- var init = opt.init || ""
15
- var partial = opt.partial || false
14
+ var init = opt.init || "";
15
+ var partial = opt.partial || false;
16
16
  if (opt.options instanceof Array) {
17
- this._options = opt.options
18
- this._regexp = undefined
17
+ this._options = opt.options;
18
+ this._regexp = undefined;
19
19
  }
20
20
  else if (opt.options instanceof RegExp) {
21
- this._options = []
22
- this._regexp = opt.options
21
+ this._options = [];
22
+ this._regexp = opt.options;
23
23
  }
24
24
  else {
25
- this._options = []
25
+ this._options = [];
26
+ this._regexp = undefined;
26
27
  }
27
- this._successHandler = opt.onSuccess
28
- this._failureHandler = opt.onFailure
29
- this.isActive = true
28
+ this._successHandler = opt.onSuccess;
29
+ this._failureHandler = opt.onFailure;
30
+ this.isActive = true;
30
31
  this.stateChangeFunc(this.isActive);
31
- this.show(element, init, partial, this._options)
32
+ this.show(element, init, partial, this._options);
32
33
  },
33
34
 
34
35
  finish: function() {
35
36
  if ((this._options.size() == 0 || this._options.include(this.getText())) && (this._regexp == undefined || this._regexp.test(this.getText()))) {
36
- this.isActive = false
37
+ this.isActive = false;
37
38
  this.stateChangeFunc(this.isActive);
38
- this.hide()
39
- if (this._successHandler) this._successHandler(this.getText())
39
+ this.hide();
40
+ if (this._successHandler) this._successHandler(this.getText());
40
41
  }
41
42
  else {
42
- this.setError()
43
+ this.setError();
43
44
  }
44
45
  },
45
46
 
46
47
  cancel: function() {
47
- this.isActive = false
48
+ this.isActive = false;
48
49
  this.stateChangeFunc(this.isActive);
49
- this.hide()
50
- if (this._failureHandler) this._failureHandler()
50
+ this.hide();
51
+ if (this._failureHandler) this._failureHandler();
51
52
  }
52
53
 
53
54
  })
@@ -20,7 +20,7 @@ Concrete.UI.AbstractDialog = Class.create({
20
20
  }.bind(this));
21
21
  Event.observe(window, 'mousemove', function(event) {
22
22
  if (this.moving) {
23
- this.dialogElement.setStyle({left: event.clientX-this.moveOffset.left, top: event.clientY-this.moveOffset.top});
23
+ this.dialogElement.setStyle({left: event.clientX-this.moveOffset.left+'px', top: event.clientY-this.moveOffset.top+'px'});
24
24
  }
25
25
  }.bind(this));
26
26
  Event.observe(window, 'click', function(event) {
@@ -62,8 +62,8 @@ Concrete.UI.AbstractDialog = Class.create({
62
62
  },
63
63
 
64
64
  open: function() {
65
- this.dialogElement.setStyle({left: (window.innerWidth-this.dialogElement.getWidth())/2, top: (window.innerHeight-this.dialogElement.getHeight())/2});
66
- this.dialogElement.down(".shadow").setStyle({width: this.dialogElement.getWidth()+10, height: this.dialogElement.getHeight()+10});
65
+ this.dialogElement.setStyle({left: (window.innerWidth-this.dialogElement.getWidth())/2+'px', top: (window.innerHeight-this.dialogElement.getHeight())/2+'px'});
66
+ this.dialogElement.down(".shadow").setStyle({width: this.dialogElement.getWidth()+10+'px', height: this.dialogElement.getHeight()+10+'px'});
67
67
  this.dialogElement.show();
68
68
  this.dialogElement.down("input").select();
69
69
  this.active = true;
@@ -45,10 +45,10 @@ Concrete.UI.LayoutManager = Class.create({
45
45
  var sb = this.sidebar;
46
46
  var sbd = this._sidebarDrag;
47
47
  var main = this.main;
48
- tb.setStyle({left: 0, top: 0, width: window.innerWidth});
49
- sb.setStyle({left: 0, top: tb.getHeight(), width: this._sidebarWidth, height: window.innerHeight-tb.getHeight()});
50
- sbd.setStyle({left: sb.getWidth(), top: tb.getHeight(), height: window.innerHeight-tb.getHeight()});
51
- main.setStyle({left: sb.getWidth()+sbd.getWidth(), top: tb.getHeight(), width: window.innerWidth-sb.getWidth()-sbd.getWidth(), height: window.innerHeight-tb.getHeight()});
48
+ tb.setStyle({left: 0, top: 0, width: window.innerWidth+'px'});
49
+ sb.setStyle({left: 0, top: tb.getHeight()+'px', width: this._sidebarWidth+'px', height: window.innerHeight-tb.getHeight()+'px'});
50
+ sbd.setStyle({left: sb.getWidth()+'px', top: tb.getHeight()+'px', height: window.innerHeight-tb.getHeight()+'px'});
51
+ main.setStyle({left: sb.getWidth()+sbd.getWidth()+'px', top: tb.getHeight()+'px', width: window.innerWidth-sb.getWidth()-sbd.getWidth()+'px', height: window.innerHeight-tb.getHeight()+'px'});
52
52
  }
53
53
 
54
54
  });
@@ -39,7 +39,7 @@ Concrete.UI.Toolbar = Class.create({
39
39
  if (left > document.viewport.getDimensions().width - this.popup.getWidth()) {
40
40
  left = document.viewport.getDimensions().width - this.popup.getWidth();
41
41
  }
42
- this.popup.setStyle({left: left, top: event.clientY+20});
42
+ this.popup.setStyle({left: left+'px', top: event.clientY+20+'px'});
43
43
  this.popup.show();
44
44
  }
45
45
  }
@@ -753,12 +753,15 @@ cellspacing="0" cellpadding="4">
753
753
  templates.html
754
754
  <syntax 2>
755
755
  style.css
756
- templates.html</tt></pre>
756
+ templates.html
757
+ ...
758
+ &lt;syntax root dir n&gt;</tt></pre>
757
759
  </div></div>
758
- <div class="paragraph"><p>There can be several syntax root directories (e.g. one which is deployed with your editor and one in the user&#8217;s home directory). The display name of a specific syntax is derived from the syntax directory within a root directory. The syntax directory should contain a file "templates.html" in case the syntax contains a HTML part. It should also contain a CSS file "style.css" and it may contain more resources (e.g. images) referenced from that stylesheet.</p></div>
760
+ <div class="paragraph"><p>There can be several syntax root directories (e.g. one which is deployed with your editor and one in the user&#8217;s home directory). The display name of a specific syntax is derived from the syntax directory within a root directory. The syntax directory should contain a file "templates.html" or "templates.haml" in case the syntax contains a HTML part. It should also contain a CSS, SASS or SCSS file and it may contain more resources (e.g. images) referenced from that stylesheet.</p></div>
761
+ <div class="paragraph"><p>HTML templates and stylesheets may be specified in HAML and SASS or SCSS format to make them more concise and readable. For this to work, <em>haml</em> needs to be installed as a gem (use "gem install haml"), the HTML templates file must be named "templates.haml" and the SASS and SCSS filenames must end with .sass and .scss. If the server is given a <em>haml eval contect</em> object (see below) the HAML templates will evaluate in this context.</p></div>
759
762
  <div class="paragraph"><p>The server will make the files in the directory of the selected syntax available via the path prefix "/syntax". It will also insert the contents of the file "template.html" in the main HTML file by replacing the placeholder comment "html templates". See below for an example.</p></div>
760
763
  <h3 id="_setting_up_the_server">Setting up the Server</h3><div style="clear:left"></div>
761
- <div class="paragraph"><p>With a working set, data provider and syntax provider in place the server can be instantiated. As an additional argument, it needs the location of its HTML root directory. The root directory should contain a file named "editor.html" which is the main HTML file as described in the next section.</p></div>
764
+ <div class="paragraph"><p>With a working set, data provider and syntax provider in place the server can be instantiated. As an additional argument, it needs the location of its HTML root directory. The root directory should contain a file named "editor.html" which is the main HTML file as described in the next section. A further option to the server is the HAML eval context which can be provided using the named argument <em>:hamlEvalContext</em>.</p></div>
762
765
  <div class="paragraph"><p>The following example code sets up an instance of <em>Concrete::Server</em>. It reads the module names as file names from the command line and uses the RGen builtin ECore meta-metamodel as metamodel (in fact this is taken form the "mmedit" metamodel editor project). It uses the <em>Concrete::IndexBuilder</em> to derive the index metamodel and the index model and it uses a <em>Concrete::Config</em> to store the preferences in the user&#8217;s home directory.</p></div>
763
766
  <div class="listingblock">
764
767
  <div class="content">
@@ -1047,7 +1050,7 @@ cellspacing="0" cellpadding="4">
1047
1050
  </div>
1048
1051
  <div id="footer">
1049
1052
  <div id="footer-text">
1050
- Last updated 2010-06-14 14:05:31 WEDT
1053
+ Last updated 2010-06-30 08:10:12 WEDT
1051
1054
  </div>
1052
1055
  </div>
1053
1056
  </body>
@@ -353,16 +353,20 @@ The workbench server supports selecting a concrete syntax from a set of availabl
353
353
  <syntax 2>
354
354
  style.css
355
355
  templates.html
356
+ ...
357
+ <syntax root dir n>
356
358
  ----
357
359
 
358
- There can be several syntax root directories (e.g. one which is deployed with your editor and one in the user's home directory). The display name of a specific syntax is derived from the syntax directory within a root directory. The syntax directory should contain a file "templates.html" in case the syntax contains a HTML part. It should also contain a CSS file "style.css" and it may contain more resources (e.g. images) referenced from that stylesheet.
360
+ There can be several syntax root directories (e.g. one which is deployed with your editor and one in the user's home directory). The display name of a specific syntax is derived from the syntax directory within a root directory. The syntax directory should contain a file "templates.html" or "templates.haml" in case the syntax contains a HTML part. It should also contain a CSS, SASS or SCSS file and it may contain more resources (e.g. images) referenced from that stylesheet.
361
+
362
+ HTML templates and stylesheets may be specified in HAML and SASS or SCSS format to make them more concise and readable. For this to work, _haml_ needs to be installed as a gem (use "gem install haml"), the HTML templates file must be named "templates.haml" and the SASS and SCSS filenames must end with .sass and .scss. If the server is given a _haml eval contect_ object (see below) the HAML templates will evaluate in this context.
359
363
 
360
364
  The server will make the files in the directory of the selected syntax available via the path prefix "/syntax". It will also insert the contents of the file "template.html" in the main HTML file by replacing the placeholder comment "html templates". See below for an example.
361
365
 
362
366
 
363
367
  === Setting up the Server ===
364
368
 
365
- With a working set, data provider and syntax provider in place the server can be instantiated. As an additional argument, it needs the location of its HTML root directory. The root directory should contain a file named "editor.html" which is the main HTML file as described in the next section.
369
+ With a working set, data provider and syntax provider in place the server can be instantiated. As an additional argument, it needs the location of its HTML root directory. The root directory should contain a file named "editor.html" which is the main HTML file as described in the next section. A further option to the server is the HAML eval context which can be provided using the named argument _:hamlEvalContext_.
366
370
 
367
371
  The following example code sets up an instance of _Concrete::Server_. It reads the module names as file names from the command line and uses the RGen builtin ECore meta-metamodel as metamodel (in fact this is taken form the "mmedit" metamodel editor project). It uses the _Concrete::IndexBuilder_ to derive the index metamodel and the index model and it uses a _Concrete::Config_ to store the preferences in the user's home directory.
368
372
 
@@ -498,7 +498,8 @@ If a constraint is violated for an element or feature, the element/feature will
498
498
  Move the mouse over such an element in order to show the error message in a popup window.</p></div>
499
499
  <h3 id="_model_information">Model Information</h3><div style="clear:left"></div>
500
500
  <div class="paragraph"><p>Depending on the concrete syntax, the feature names might be hidden. When moving the mouse over a model value, the name of the
501
- feature that value belongs to will be shown. Also for references, the full identifier will be shown.</p></div>
501
+ feature that value belongs to will be shown. Also for references, the full identifier, and in case of external references to other models,
502
+ the module identifier will be shown.</p></div>
502
503
  </div>
503
504
  <h2 id="_workbench">Workbench</h2>
504
505
  <div class="sectionbody">
@@ -687,7 +688,7 @@ cellspacing="0" cellpadding="4">
687
688
  </div>
688
689
  <div id="footer">
689
690
  <div id="footer-text">
690
- Last updated 2010-06-13 23:51:34 WEDT
691
+ Last updated 2010-06-25 07:58:46 WEDT
691
692
  </div>
692
693
  </div>
693
694
  </body>
@@ -159,7 +159,8 @@ Move the mouse over such an element in order to show the error message in a popu
159
159
  === Model Information ===
160
160
 
161
161
  Depending on the concrete syntax, the feature names might be hidden. When moving the mouse over a model value, the name of the
162
- feature that value belongs to will be shown. Also for references, the full identifier will be shown.
162
+ feature that value belongs to will be shown. Also for references, the full identifier, and in case of external references to other models,
163
+ the module identifier will be shown.
163
164
 
164
165
 
165
166
  == Workbench ==
@@ -1,9 +1,11 @@
1
+ require 'andand'
2
+
1
3
  module Concrete
2
4
 
3
5
  class ConcreteSyntaxProvider
4
6
 
5
7
  class ConcreteSyntax
6
- attr_accessor :ident, :dir, :name, :desc, :htmlTemplates, :cssStyleFile
8
+ attr_accessor :ident, :dir, :name, :desc
7
9
  end
8
10
 
9
11
  def initialize(configDirs, logger, config=nil)
@@ -22,7 +24,7 @@ class ConcreteSyntaxProvider
22
24
 
23
25
  def selectSyntax(ident)
24
26
  @selectedSyntax = syntaxes.find{|s| s.ident == ident}
25
- @config.andand.storeValue("concrete_syntax", ident.to_s)
27
+ @config.andand.storeValue("concrete_syntax", ident.to_s) if @selectedSyntax
26
28
  end
27
29
 
28
30
  def syntaxesAsJson
@@ -38,25 +40,17 @@ class ConcreteSyntaxProvider
38
40
  Dir.entries(cd).sort.each do |sd|
39
41
  next if sd == "." || sd == ".."
40
42
  syntaxDir = cd+"/"+sd
41
- templatesFile = syntaxDir + "/templates.html"
42
- styleFile = syntaxDir + "/style.css"
43
- unless File.exist?(templatesFile) || File.exist?(styleFile)
44
- @logger.warn("Concrete syntax dir without a templates.html or a style.css: #{syntaxDir}")
45
- next
46
- end
47
43
  s = ConcreteSyntax.new
48
44
  s.ident = syntaxDir.gsub("\\","/")
49
45
  s.dir = syntaxDir
50
46
  s.name = sd.split(/[_\W]/).collect{|w| w.capitalize}.join(" ")
51
47
  s.desc = ""
52
- s.cssStyleFile = styleFile if File.exist?(styleFile)
53
- s.htmlTemplates = File.read(templatesFile) if File.exist?(templatesFile)
54
48
  result << s
55
49
  end
56
50
  end
57
51
  result
58
52
  end
59
-
53
+
60
54
  end
61
55
 
62
56
  end
@@ -0,0 +1,57 @@
1
+ require 'rgen/ecore/ecore'
2
+
3
+ module Concrete
4
+
5
+ # Objects of this class are meant to be used as HAML eval context
6
+ # Context methods provide convenient access to the metamodel
7
+ # The metamodel is expected to be a RGen ECore metamodel
8
+ class HamlEvalContext
9
+ def initialize(mm)
10
+ @mm = mm
11
+ @metaclassesByName = nil
12
+ end
13
+
14
+ def metaclasses
15
+ loadMetaclasses unless @metaclassesByName
16
+ @metaclassesByName.values
17
+ end
18
+
19
+ def metaclass(name)
20
+ loadMetaclasses unless @metaclassesByName
21
+ @metaclassesByName[name]
22
+ end
23
+
24
+ def metaclassFeatures(name, options={})
25
+ exclusions = options[:except] || []
26
+ if exclusions.is_a?(Array)
27
+ metaclass(name).eAllStructuralFeatures.reject{|f| exclusions.include?(f.name)}
28
+ else
29
+ metaclass(name).eAllStructuralFeatures.reject{|f| exclusions == f.name}
30
+ end
31
+ end
32
+
33
+ def metaclassContainments(name, options={})
34
+ metaclassFeatures(name, options).select{|f| f.is_a?(RGen::ECore::EReference) && f.containment}
35
+ end
36
+
37
+ def metaclassReferences(name, options={})
38
+ metaclassFeatures(name, options).select{|f| f.is_a?(RGen::ECore::EReference) && !f.containment}
39
+ end
40
+
41
+ def metaclassAttributes(name, options={})
42
+ metaclassFeatures(name, options).select{|f| f.is_a?(RGen::ECore::EAttribute)}
43
+ end
44
+
45
+ private
46
+
47
+ def loadMetaclasses
48
+ @metaclassesByName = {}
49
+ @mm.eAllClasses.each do |c|
50
+ @metaclassesByName[c.name] = c
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
@@ -1,4 +1,9 @@
1
1
  require 'webrick'
2
+ begin
3
+ require 'haml'
4
+ require 'sass'
5
+ rescue LoadError
6
+ end
2
7
 
3
8
  module Concrete
4
9
 
@@ -9,6 +14,8 @@ class Server
9
14
  @dataProvider = dataProvider
10
15
  @syntaxProvider = syntaxProvider
11
16
  @htmlRoot = htmlRoot
17
+ @logger = options[:logger]
18
+ @hamlEvalContext = options[:hamlEvalContext]
12
19
  @mutex = Mutex.new
13
20
  @server = WEBrick::HTTPServer.new(:Port => (options[:port] || 1234))
14
21
  @server.mount_proc("/") do |req, res|
@@ -27,16 +34,15 @@ class Server
27
34
  def handleRequest(req, res)
28
35
  if req.path == "/"
29
36
  editorHtml = File.read(@htmlRoot+"/editor.html")
30
- editorHtml.sub!(/<!--\s+html templates\s+-->/, @syntaxProvider.selectedSyntax.htmlTemplates) if @syntaxProvider.andand.selectedSyntax.andand.htmlTemplates
37
+ templatesData = htmlTemplatesData(@syntaxProvider.selectedSyntax.dir) if @syntaxProvider.selectedSyntax
38
+ editorHtml.sub!(/<!--\s+html templates\s+-->/, templatesData) if templatesData
31
39
  res.body = editorHtml
32
40
  elsif req.path =~ /^\/html\/(.*)/
33
41
  File.open(@htmlRoot+"/"+$1, "rb") do |f|
34
42
  res.body = f.read
35
43
  end
36
44
  elsif req.path =~ /^\/syntax\/(.*)/ && @syntaxProvider.selectedSyntax
37
- File.open(@syntaxProvider.selectedSyntax.dir+"/"+$1, "rb") do |f|
38
- res.body = f.read
39
- end
45
+ res.body = syntaxFileData(@syntaxProvider.selectedSyntax.dir+"/"+$1)
40
46
  elsif req.path =~ /^\/concrete\/(.*)/
41
47
  File.open(File.dirname(__FILE__)+"/../../"+$1, "rb") do |f|
42
48
  res.body = f.read
@@ -85,7 +91,36 @@ class Server
85
91
  # error
86
92
  end
87
93
  end
88
-
94
+
95
+ def syntaxFileData(fileName)
96
+ if haveHaml? && fileName =~ /(\.sass|\.scss)$/
97
+ Sass::Engine.new(File.read(fileName)).render
98
+ else
99
+ File.open(fileName, "rb") do |f|
100
+ f.read
101
+ end
102
+ end
103
+ end
104
+
105
+ def htmlTemplatesData(syntaxDir)
106
+ if haveHaml? && File.exist?(syntaxDir + "/templates.haml")
107
+ templatesFile = syntaxDir + "/templates.haml"
108
+ @logger.info("Using HAML templates file #{templatesFile}") if @logger
109
+ engine = Haml::Engine.new(File.read(templatesFile))
110
+ engine.render(@hamlEvalContext || Object.new)
111
+ elsif File.exist?(syntaxDir + "/templates.html")
112
+ templatesFile = syntaxDir + "/templates.html"
113
+ @logger.info("Using HTML templates file #{templatesFile}") if @logger
114
+ File.read(templatesFile)
115
+ end
116
+ end
117
+
118
+ def haveHaml?
119
+ begin
120
+ Haml
121
+ rescue NameError
122
+ end
123
+ end
89
124
  end
90
125
 
91
126
  end
data/rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rake/gempackagetask'
2
2
 
3
3
  GemSpec = Gem::Specification.new do |s|
4
4
  s.name = "concrete"
5
- s.version = "0.2.0"
5
+ s.version = "0.2.1"
6
6
  s.date = Time.now.strftime("%Y-%m-%d")
7
7
  s.summary = %q{Concrete is a lightweight, web-based model editor which can be configured for different DSLs}
8
8
  s.authors = ["Martin Thiede"]
@@ -0,0 +1,127 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/../lib")
2
+
3
+ require 'test/unit'
4
+ require 'fileutils'
5
+ require 'concrete/concrete_syntax_provider'
6
+ begin
7
+ require 'haml'
8
+ rescue LoadError
9
+ end
10
+
11
+ class ConcreteSyntaxProviderTest < Test::Unit::TestCase
12
+
13
+ TestDir = File.dirname(__FILE__)+"/concrete_syntax_provider_test"
14
+
15
+ class LoggerMock
16
+ attr_reader :messages
17
+ def initialize; @messages = []; end
18
+ def info(msg)
19
+ @messages << "INFO: #{msg}"
20
+ end
21
+ def warn(msg)
22
+ @messages << "WARN: #{msg}"
23
+ end
24
+ def error(msg)
25
+ @messages << "ERROR: #{msg}"
26
+ end
27
+ end
28
+
29
+ class ConfigMock
30
+ attr_reader :values
31
+ def initialize; @values = {}; end
32
+ def loadValue(ident)
33
+ @values[ident]
34
+ end
35
+ def storeValue(ident, value)
36
+ @values[ident] = value
37
+ end
38
+ end
39
+
40
+ def test_syntaxes_no_dirs
41
+ logger = LoggerMock.new
42
+ sp = Concrete::ConcreteSyntaxProvider.new([], logger)
43
+ assert_equal [], sp.syntaxes
44
+ assert_equal '{ "syntaxes": [], "selected": "" }', sp.syntaxesAsJson
45
+ assert_equal [], logger.messages
46
+ end
47
+
48
+ def test_syntaxes_non_existing_dir
49
+ logger = LoggerMock.new
50
+ sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/doesNotExist"], logger)
51
+ assert_equal [], sp.syntaxes
52
+ assert_equal '{ "syntaxes": [], "selected": "" }', sp.syntaxesAsJson
53
+ assert_equal [], logger.messages
54
+ end
55
+
56
+ def test_syntaxes_no_syntaxes
57
+ logger = LoggerMock.new
58
+ raise "bad preconditions" unless File.exist?(TestDir+"/syntaxDir0")
59
+ sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir0"], logger)
60
+ assert_equal [], sp.syntaxes
61
+ assert_equal '{ "syntaxes": [], "selected": "" }', sp.syntaxesAsJson
62
+ assert_equal [], logger.messages
63
+ end
64
+
65
+ def test_syntaxes_empty_syntax
66
+ logger = LoggerMock.new
67
+ sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir1"], logger)
68
+ assert_equal 1, sp.syntaxes.size
69
+ assert_equal "Empty Syntax", sp.syntaxes.first.name
70
+ assert_equal [], logger.messages
71
+ assert_equal '{ "syntaxes": [' +
72
+ '{ "ident": "'+TestDir+'/syntaxDir1/empty_syntax", "name": "Empty Syntax" }' +
73
+ '], "selected": "" }', sp.syntaxesAsJson
74
+ end
75
+
76
+ def test_syntaxes_common
77
+ logger = LoggerMock.new
78
+ sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir2"], logger)
79
+ syntaxes = sp.syntaxes
80
+ assert_equal 1, syntaxes.size
81
+ assert_equal "First Syntax", syntaxes.first.name
82
+ assert_equal TestDir+"/syntaxDir2/first_syntax", syntaxes.first.ident
83
+ assert_equal '{ "syntaxes": [' +
84
+ '{ "ident": "'+TestDir+'/syntaxDir2/first_syntax", "name": "First Syntax" }' +
85
+ '], "selected": "" }', sp.syntaxesAsJson
86
+ assert_equal [], logger.messages
87
+ end
88
+
89
+ def test_selectSyntax_no_syntax
90
+ logger = LoggerMock.new
91
+ sp = Concrete::ConcreteSyntaxProvider.new([], logger)
92
+ assert_nothing_raised do
93
+ sp.selectSyntax("dummy")
94
+ end
95
+ assert_nil sp.selectedSyntax
96
+ end
97
+
98
+ def test_selectSyntax_no_config
99
+ logger = LoggerMock.new
100
+ sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir2", TestDir+"/syntaxDir3"], logger)
101
+ assert_nothing_raised do
102
+ sp.selectSyntax("dummy")
103
+ end
104
+ assert_equal "First Syntax", sp.selectedSyntax.name
105
+ sp.selectSyntax(TestDir+"/syntaxDir3/haml_syntax")
106
+ assert_equal "Haml Syntax", sp.selectedSyntax.name
107
+ end
108
+
109
+ def test_selectSyntax_load_config
110
+ logger = LoggerMock.new
111
+ config = ConfigMock.new
112
+ config.values["concrete_syntax"] = TestDir+"/syntaxDir3/haml_syntax"
113
+ sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir2", TestDir+"/syntaxDir3"], logger, config)
114
+ assert_equal "Haml Syntax", sp.selectedSyntax.name
115
+ end
116
+
117
+ def test_selectSyntax_store_config
118
+ logger = LoggerMock.new
119
+ config = ConfigMock.new
120
+ sp = Concrete::ConcreteSyntaxProvider.new([TestDir+"/syntaxDir2", TestDir+"/syntaxDir3"], logger, config)
121
+ sp.selectSyntax("dummy")
122
+ assert_equal({}, config.values)
123
+ sp.selectSyntax(TestDir+"/syntaxDir3/haml_syntax" )
124
+ assert_equal({"concrete_syntax" => TestDir+"/syntaxDir3/haml_syntax" }, config.values)
125
+ end
126
+
127
+ end
@@ -2,4 +2,6 @@ require 'file_cache_map_test'
2
2
  require 'index_builder_test'
3
3
  require 'metamodel_test'
4
4
  require 'working_set_test'
5
+ require 'concrete_syntax_provider_test'
6
+ require 'haml_eval_context_test'
5
7
 
@@ -0,0 +1,46 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
+
3
+ require 'test/unit'
4
+ require 'rgen/environment'
5
+ require 'rgen/array_extensions'
6
+ require 'rgen/ecore/ecore'
7
+ require 'concrete/haml_eval_context'
8
+ begin
9
+ require 'haml'
10
+ rescue LoadError
11
+ end
12
+
13
+ class HamlEvalContextTest < Test::Unit::TestCase
14
+
15
+ def test_simple
16
+ return unless haveHaml?
17
+ context = Concrete::HamlEvalContext.new(RGen::ECore.ecore)
18
+ engine = Haml::Engine.new("= metaclass('EClass').name")
19
+ assert_equal "EClass\n", engine.render(context)
20
+ engine = Haml::Engine.new("= metaclasses.size")
21
+ assert_equal "18\n", engine.render(context)
22
+ engine = Haml::Engine.new("= metaclassFeatures('EEnum').size")
23
+ assert_equal "8\n", engine.render(context)
24
+ engine = Haml::Engine.new("= metaclassContainments('EEnum').size")
25
+ assert_equal "2\n", engine.render(context)
26
+ engine = Haml::Engine.new("= metaclassReferences('EEnum').size")
27
+ assert_equal "1\n", engine.render(context)
28
+ engine = Haml::Engine.new("= metaclassAttributes('EEnum').size")
29
+ assert_equal "5\n", engine.render(context)
30
+ engine = Haml::Engine.new("= metaclassAttributes('EEnum', :except => ['name']).size")
31
+ assert_equal "4\n", engine.render(context)
32
+ engine = Haml::Engine.new("= metaclassAttributes('EEnum', :except => 'name').size")
33
+ assert_equal "4\n", engine.render(context)
34
+ engine = Haml::Engine.new("= metaclassAttributes('EEnum', :except => 'namex').size")
35
+ assert_equal "5\n", engine.render(context)
36
+ end
37
+
38
+ def haveHaml?
39
+ begin
40
+ Haml
41
+ rescue NameError
42
+ end
43
+ end
44
+
45
+ end
46
+
@@ -1,4 +1,37 @@
1
1
  { "_class": "EPackage", "name": "ECore", "elements": [
2
+ { "_class": "EClass", "name": "EAnnotation", "elements": [
3
+ { "_class": "EAttribute", "name": "source" },
4
+ { "_class": "EReference", "name": "eModelElement" },
5
+ { "_class": "EReference", "name": "details" },
6
+ { "_class": "EReference", "name": "contents" },
7
+ { "_class": "EReference", "name": "references" }] },
8
+ { "_class": "EClass", "name": "EDataType", "elements": [
9
+ { "_class": "EAttribute", "name": "serializable" }] },
10
+ { "_class": "EClass", "name": "EClassifier", "elements": [
11
+ { "_class": "EAttribute", "name": "defaultValue" },
12
+ { "_class": "EAttribute", "name": "instanceClass" },
13
+ { "_class": "EAttribute", "name": "instanceClassName" },
14
+ { "_class": "EReference", "name": "ePackage" }] },
15
+ { "_class": "EClass", "name": "EOperation", "elements": [
16
+ { "_class": "EReference", "name": "eContainingClass" },
17
+ { "_class": "EReference", "name": "eParameters" },
18
+ { "_class": "EReference", "name": "eExceptions" }] },
19
+ { "_class": "EClass", "name": "EClass", "elements": [
20
+ { "_class": "EAttribute", "name": "abstract" },
21
+ { "_class": "EAttribute", "name": "interface" },
22
+ { "_class": "EReference", "name": "eIDAttribute" },
23
+ { "_class": "EReference", "name": "eAllAttributes" },
24
+ { "_class": "EReference", "name": "eAllContainments" },
25
+ { "_class": "EReference", "name": "eAllOperations" },
26
+ { "_class": "EReference", "name": "eAllReferences" },
27
+ { "_class": "EReference", "name": "eAllStructuralFeatures" },
28
+ { "_class": "EReference", "name": "eAllSuperTypes" },
29
+ { "_class": "EReference", "name": "eAttributes" },
30
+ { "_class": "EReference", "name": "eReferences" },
31
+ { "_class": "EReference", "name": "eOperations" },
32
+ { "_class": "EReference", "name": "eStructuralFeatures" },
33
+ { "_class": "EReference", "name": "eSuperTypes" },
34
+ { "_class": "EReference", "name": "eSubTypes" }] },
2
35
  { "_class": "EClass", "name": "EModelElement", "elements": [
3
36
  { "_class": "EReference", "name": "eAnnotations" }] },
4
37
  { "_class": "EClass", "name": "EReference", "elements": [
@@ -49,37 +82,4 @@
49
82
  { "_class": "EClass", "name": "EEnum", "elements": [
50
83
  { "_class": "EReference", "name": "eLiterals" }] },
51
84
  { "_class": "EClass", "name": "EParameter", "elements": [
52
- { "_class": "EReference", "name": "eOperation" }] },
53
- { "_class": "EClass", "name": "EAnnotation", "elements": [
54
- { "_class": "EAttribute", "name": "source" },
55
- { "_class": "EReference", "name": "eModelElement" },
56
- { "_class": "EReference", "name": "details" },
57
- { "_class": "EReference", "name": "contents" },
58
- { "_class": "EReference", "name": "references" }] },
59
- { "_class": "EClass", "name": "EDataType", "elements": [
60
- { "_class": "EAttribute", "name": "serializable" }] },
61
- { "_class": "EClass", "name": "EClassifier", "elements": [
62
- { "_class": "EAttribute", "name": "defaultValue" },
63
- { "_class": "EAttribute", "name": "instanceClass" },
64
- { "_class": "EAttribute", "name": "instanceClassName" },
65
- { "_class": "EReference", "name": "ePackage" }] },
66
- { "_class": "EClass", "name": "EOperation", "elements": [
67
- { "_class": "EReference", "name": "eContainingClass" },
68
- { "_class": "EReference", "name": "eParameters" },
69
- { "_class": "EReference", "name": "eExceptions" }] },
70
- { "_class": "EClass", "name": "EClass", "elements": [
71
- { "_class": "EAttribute", "name": "abstract" },
72
- { "_class": "EAttribute", "name": "interface" },
73
- { "_class": "EReference", "name": "eIDAttribute" },
74
- { "_class": "EReference", "name": "eAllAttributes" },
75
- { "_class": "EReference", "name": "eAllContainments" },
76
- { "_class": "EReference", "name": "eAllOperations" },
77
- { "_class": "EReference", "name": "eAllReferences" },
78
- { "_class": "EReference", "name": "eAllStructuralFeatures" },
79
- { "_class": "EReference", "name": "eAllSuperTypes" },
80
- { "_class": "EReference", "name": "eAttributes" },
81
- { "_class": "EReference", "name": "eReferences" },
82
- { "_class": "EReference", "name": "eOperations" },
83
- { "_class": "EReference", "name": "eStructuralFeatures" },
84
- { "_class": "EReference", "name": "eSuperTypes" },
85
- { "_class": "EReference", "name": "eSubTypes" }] }] }
85
+ { "_class": "EReference", "name": "eOperation" }] }] }
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concrete
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 1
9
+ version: 0.2.1
5
10
  platform: ruby
6
11
  authors:
7
12
  - Martin Thiede
@@ -9,29 +14,39 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-06-14 00:00:00 +02:00
17
+ date: 2010-09-21 00:00:00 +02:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: rgen
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
20
25
  requirements:
21
26
  - - ">="
22
27
  - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 5
31
+ - 2
23
32
  version: 0.5.2
24
- version:
33
+ type: :runtime
34
+ version_requirements: *id001
25
35
  - !ruby/object:Gem::Dependency
26
36
  name: andand
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
30
40
  requirements:
31
41
  - - ">="
32
42
  - !ruby/object:Gem::Version
43
+ segments:
44
+ - 1
45
+ - 3
46
+ - 1
33
47
  version: 1.3.1
34
- version:
48
+ type: :runtime
49
+ version_requirements: *id002
35
50
  description:
36
51
  email:
37
52
  executables: []
@@ -127,6 +142,7 @@ files:
127
142
  - lib/concrete/concrete_syntax_provider.rb
128
143
  - lib/concrete/config.rb
129
144
  - lib/concrete/file_cache_map.rb
145
+ - lib/concrete/haml_eval_context.rb
130
146
  - lib/concrete/index_builder.rb
131
147
  - lib/concrete/metamodel/concrete_mmm.rb
132
148
  - lib/concrete/metamodel/ecore_to_concrete.rb
@@ -143,9 +159,14 @@ files:
143
159
  - redist/scriptaculous/slider.js
144
160
  - redist/scriptaculous/sound.js
145
161
  - redist/scriptaculous/unittest.js
162
+ - test/concrete_syntax_provider_test/syntaxDir2/first_syntax/style.css
163
+ - test/concrete_syntax_provider_test/syntaxDir3/haml_syntax/templates.haml
164
+ - test/concrete_syntax_provider_test/syntaxDir3/html_syntax/templates.html
165
+ - test/concrete_syntax_provider_test.rb
146
166
  - test/concrete_test.rb
147
167
  - test/file_cache_map_test/testdir/fileA
148
168
  - test/file_cache_map_test.rb
169
+ - test/haml_eval_context_test.rb
149
170
  - test/index_builder_test/ecore_index.js
150
171
  - test/index_builder_test/ecore_index_expected.js
151
172
  - test/index_builder_test.rb
@@ -179,21 +200,27 @@ require_paths:
179
200
  - lib
180
201
  - lib
181
202
  required_ruby_version: !ruby/object:Gem::Requirement
203
+ none: false
182
204
  requirements:
183
205
  - - ">="
184
206
  - !ruby/object:Gem::Version
207
+ segments:
208
+ - 1
209
+ - 8
210
+ - 6
185
211
  version: 1.8.6
186
- version:
187
212
  required_rubygems_version: !ruby/object:Gem::Requirement
213
+ none: false
188
214
  requirements:
189
215
  - - ">="
190
216
  - !ruby/object:Gem::Version
217
+ segments:
218
+ - 0
191
219
  version: "0"
192
- version:
193
220
  requirements: []
194
221
 
195
222
  rubyforge_project:
196
- rubygems_version: 1.3.5
223
+ rubygems_version: 1.3.7
197
224
  signing_key:
198
225
  specification_version: 3
199
226
  summary: Concrete is a lightweight, web-based model editor which can be configured for different DSLs