comet-cpp 0.9.0
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.
- checksums.yaml +7 -0
- data/bin/comet-html +69 -0
- data/bin/comet-make +53 -0
- data/bin/comet-new +62 -0
- data/bin/comet-web +14 -0
- data/lib/comet-html/generator.rb +220 -0
- data/lib/comet-html/header-generator.rb +145 -0
- data/lib/comet-html/parser-binding.rb +42 -0
- data/lib/comet-html/parser-class.rb +168 -0
- data/lib/comet-html/parser-context.rb +61 -0
- data/lib/comet-html/parser-reference.rb +98 -0
- data/lib/comet-html/parser-repeater.rb +58 -0
- data/lib/comet-html/parser-slot.rb +108 -0
- data/lib/comet-html/source-generator.rb +285 -0
- data/lib/comet-html/utils.rb +88 -0
- data/lib/guard/comet-html.rb +32 -0
- data/lib/guard/comet.rb +36 -0
- data/vendor/project/Gemfile +4 -0
- data/vendor/project/Guardfile +5 -0
- data/vendor/project/app/application.hpp +29 -0
- data/vendor/project/app/collections/.gitkeep +0 -0
- data/vendor/project/app/controllers/.gitkeep +0 -0
- data/vendor/project/app/main.cpp +6 -0
- data/vendor/project/app/models/.gitkeep +0 -0
- data/vendor/project/app/routes.cpp +7 -0
- data/vendor/project/app/views/layouts/.gitkeep +0 -0
- data/vendor/project/public/index.html +7 -0
- data/vendor/src/anchorable_element.hpp +79 -0
- data/vendor/src/append_semantics.hpp +73 -0
- data/vendor/src/bindable.cpp +99 -0
- data/vendor/src/bindable.hpp +106 -0
- data/vendor/src/cheerp_parse_cookie_values.cpp +58 -0
- data/vendor/src/comment_element.cpp +11 -0
- data/vendor/src/comment_element.hpp +17 -0
- data/vendor/src/cookies.cpp +94 -0
- data/vendor/src/cookies.hpp +60 -0
- data/vendor/src/custom_element.hpp +61 -0
- data/vendor/src/datatree.cpp +198 -0
- data/vendor/src/datatree.hpp +233 -0
- data/vendor/src/document.cpp +62 -0
- data/vendor/src/document.hpp +31 -0
- data/vendor/src/element.cpp +358 -0
- data/vendor/src/element.hpp +138 -0
- data/vendor/src/events.hpp +76 -0
- data/vendor/src/exception.cpp +13 -0
- data/vendor/src/exception.hpp +11 -0
- data/vendor/src/from_string.cpp +99 -0
- data/vendor/src/from_string.hpp +37 -0
- data/vendor/src/globals.cpp +6 -0
- data/vendor/src/globals.hpp +15 -0
- data/vendor/src/http.cpp +93 -0
- data/vendor/src/http.hpp +72 -0
- data/vendor/src/lexical_cast.hpp +51 -0
- data/vendor/src/local_storage.cpp +75 -0
- data/vendor/src/local_storage.hpp +53 -0
- data/vendor/src/mvc/collection.hpp +154 -0
- data/vendor/src/mvc/controller.hpp +59 -0
- data/vendor/src/mvc/id_type.hpp +9 -0
- data/vendor/src/mvc/layout.hpp +44 -0
- data/vendor/src/mvc/model.cpp +89 -0
- data/vendor/src/mvc/model.hpp +50 -0
- data/vendor/src/object.cpp +71 -0
- data/vendor/src/object.hpp +298 -0
- data/vendor/src/parse_cookie_values.hpp +12 -0
- data/vendor/src/promise.cpp +50 -0
- data/vendor/src/promise.hpp +43 -0
- data/vendor/src/repeater.hpp +116 -0
- data/vendor/src/router.cpp +62 -0
- data/vendor/src/router.hpp +34 -0
- data/vendor/src/router_base.hpp +107 -0
- data/vendor/src/signal.hpp +150 -0
- data/vendor/src/slot_element.hpp +61 -0
- data/vendor/src/url.cpp +19 -0
- data/vendor/src/url.hpp +15 -0
- data/vendor/src/window.cpp +22 -0
- data/vendor/src/window.hpp +24 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 76cf704d8d362f1b97c3f6fb318d9176899355ed9e59d868d777cc05f81ee72a
|
4
|
+
data.tar.gz: d5fb5a73fe2a213689448bb1579cf9eec90339fc52df6273435ebb359baabbcc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c4c4858560da8cc6d439028fdc4c8fa19906018681c425e1eee1e537243d26d3caf0769050aa434923479c061f89a10b437276a0127735a3718b5d544d457aa9
|
7
|
+
data.tar.gz: cd4b469ae6f9e3162f8520311fbcf1c67df47346a55bb9752b610d7f7dd6cbb0faa32d9e450ce5580bd5caa746c4f86d3471b593e43f1f5f00deb7290cd79458
|
data/bin/comet-html
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'json'
|
5
|
+
require 'comet-html/generator'
|
6
|
+
|
7
|
+
@source_path = "app"
|
8
|
+
@output_path = "comet-elements/html"
|
9
|
+
@config_path = "config/comet.json"
|
10
|
+
|
11
|
+
OptionParser.new do |opts|
|
12
|
+
opts.on "-i PATH", "--source-path=PATH" do |v| @source_path = v end
|
13
|
+
opts.on "-o PATH", "--output=PATH" do |v| @output_path = v end
|
14
|
+
opts.on "-c PATH", "--config=PATH" do |v| @config_path = v end
|
15
|
+
end.parse!
|
16
|
+
|
17
|
+
@source_path = File.expand_path(@source_path)
|
18
|
+
@output_path = File.expand_path(@output_path)
|
19
|
+
@config_path = File.expand_path(@config_path)
|
20
|
+
|
21
|
+
def purge_old_files whitelist
|
22
|
+
Dir["#{@output_path}/**/*"].each do |file|
|
23
|
+
next if File.directory? file
|
24
|
+
File.delete file unless whitelist.include? file
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_if_content_changed file, content
|
29
|
+
if !File.exists?(file) || File.read(file) != content
|
30
|
+
File.open file, 'w' do |f| f.write content end
|
31
|
+
puts "[comet] Generated #{file}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
files = Dir["#{@source_path}/**/*.html"]
|
36
|
+
config = if File.exists?(@config_path) then JSON.parse(File.read @config_path) else nil end
|
37
|
+
success = true
|
38
|
+
current_filename = nil
|
39
|
+
|
40
|
+
begin
|
41
|
+
generated_files = []
|
42
|
+
files.each do |file|
|
43
|
+
current_filename = file
|
44
|
+
generator = ::Comet::Generator.new @output_path, @source_path, file
|
45
|
+
generator.set_config config unless config.nil?
|
46
|
+
header_file = generator.compiled_header_path
|
47
|
+
source_file = generator.compiled_source_path
|
48
|
+
|
49
|
+
FileUtils.mkdir_p File.dirname(header_file)
|
50
|
+
code = generator.generate
|
51
|
+
write_if_content_changed header_file, code[:header]
|
52
|
+
write_if_content_changed source_file, code[:source]
|
53
|
+
generated_files << header_file << source_file
|
54
|
+
rescue ::Comet::ParseError => e
|
55
|
+
STDERR.puts "[comet] parse error at #{current_filename}:#{e.line}: #{e.message}"
|
56
|
+
success = false
|
57
|
+
rescue ::Comet::HtmlParseError => e
|
58
|
+
STDERR.puts "[comet] parse error at #{current_filename}:#{e.message}"
|
59
|
+
success = false
|
60
|
+
rescue ::Comet::LoadError => e
|
61
|
+
STDERR.puts "[comet] #{e.message}"
|
62
|
+
success = false
|
63
|
+
rescue StandardError => e
|
64
|
+
STDERR.puts e.message
|
65
|
+
e.backtrace.each do |line| STDERR.puts line end
|
66
|
+
success = false
|
67
|
+
end
|
68
|
+
purge_old_files generated_files
|
69
|
+
end
|
data/bin/comet-make
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'pathname'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pty'
|
6
|
+
|
7
|
+
@cheerp_path = "/opt/cheerp"
|
8
|
+
@build_type = "RELEASE"
|
9
|
+
@build_path = ".comet-build"
|
10
|
+
@cmakelists_path = "./"
|
11
|
+
@output_path = "public"
|
12
|
+
|
13
|
+
OptionParser.new do |opts|
|
14
|
+
opts.on "-c PATH", "--cheerp-path=PATH" do |v| @cheerp_path = v end
|
15
|
+
opts.on "-g", "--debug" do |v| @build_type = "DEBUG" end
|
16
|
+
opts.on "-i PATH", "--cmakelists=PATH" do |v| @cmakelists_path = v end
|
17
|
+
opts.on "-o PATH", "--output=PATH" do |v| @output_path = v end
|
18
|
+
end.parse!
|
19
|
+
|
20
|
+
@cmakelists_path = File.expand_path @cmakelists_path
|
21
|
+
@output_path = File.expand_path @output_path
|
22
|
+
@build_path = File.expand_path @build_path
|
23
|
+
@cheerp_path = File.expand_path @cheerp_path
|
24
|
+
|
25
|
+
cmake_options = []
|
26
|
+
cmake_options << "-DCMAKE_TOOLCHAIN_FILE=#{@cheerp_path}/share/cmake/Modules/CheerpToolchain.cmake"
|
27
|
+
cmake_options << "-DCMAKE_BUILD_TYPE=#{@build_type}"
|
28
|
+
|
29
|
+
def run_command cmd
|
30
|
+
puts "+ #{cmd}"
|
31
|
+
PTY.spawn(cmd) do |stdout,stdin,pid|
|
32
|
+
begin
|
33
|
+
stdout.each {|line| print line}
|
34
|
+
rescue Errno::EIO
|
35
|
+
end
|
36
|
+
Process.wait(pid)
|
37
|
+
end
|
38
|
+
exit -1 unless $?.success?
|
39
|
+
end
|
40
|
+
|
41
|
+
FileUtils.mkdir_p @build_path
|
42
|
+
|
43
|
+
Dir.chdir @build_path do
|
44
|
+
run_command "cmake #{cmake_options.join ' '} #{@cmakelists_path}"
|
45
|
+
run_command "make"
|
46
|
+
end
|
47
|
+
|
48
|
+
FileUtils.mkdir_p @output_path
|
49
|
+
Dir["#{@build_path}/*.{js,js.map}"].each do |target|
|
50
|
+
path = Pathname.new target
|
51
|
+
basename = path.basename
|
52
|
+
FileUtils.mv target, "#{@output_path}/#{@basename}"
|
53
|
+
end
|
data/bin/comet-new
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
@build_path = ".comet-build"
|
6
|
+
@vendor_path = "#{@build_path}/vendor"
|
7
|
+
@project_dir = "./"
|
8
|
+
@project_name = "project-name"
|
9
|
+
@skip_project = false
|
10
|
+
|
11
|
+
OptionParser.new do |opts|
|
12
|
+
opts.on "-p PATH", "--project-path=PATH" do |v| @project_dir = v end
|
13
|
+
opts.on "-n NAME", "--name=NAME" do |v| @project_name = v end
|
14
|
+
opts.on "-v PATH", "--vendor-path=PATH" do |v| @vendor_path = v end
|
15
|
+
opts.on "-z", "--skip-project-files" do |v| @skip_project = v end
|
16
|
+
end.parse!
|
17
|
+
|
18
|
+
@build_path = File.expand_path @build_path
|
19
|
+
@project_dir = File.expand_path @project_dir
|
20
|
+
@vendor_path = File.expand_path @vendor_path
|
21
|
+
@comet_src_path = "#{@vendor_path}/comet"
|
22
|
+
|
23
|
+
FileUtils.mkdir_p @comet_src_path
|
24
|
+
|
25
|
+
gemspec = Gem::Specification.find_all_by_name("comet-cpp").first
|
26
|
+
vendor_dir = File.expand_path "#{gemspec.bin_dir}/../vendor"
|
27
|
+
src_dir = vendor_dir + "/src"
|
28
|
+
app_dir = vendor_dir + "/project"
|
29
|
+
|
30
|
+
def initialize_directory src_dir, output_dir, override
|
31
|
+
Dir["#{src_dir}/**/*"].each do |filepath|
|
32
|
+
next if File.directory? filepath
|
33
|
+
relative_path = filepath[src_dir.length + 1..-1]
|
34
|
+
dest_path = output_dir + '/' + relative_path
|
35
|
+
FileUtils.mkdir_p(File.dirname dest_path)
|
36
|
+
if !File.exists?(dest_path) || override
|
37
|
+
FileUtils.cp filepath, dest_path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
initialize_directory src_dir, @comet_src_path, true
|
43
|
+
initialize_directory app_dir, @project_dir, false unless @skip_project
|
44
|
+
|
45
|
+
File.open "#{@project_dir}/CMakeLists.txt", "w" do |file|
|
46
|
+
relative_vendor_path = Pathname.new(@vendor_path).relative_path_from(Pathname.new(@project_dir)).to_s
|
47
|
+
file.write <<EOF
|
48
|
+
cmake_minimum_required(VERSION 3.0)
|
49
|
+
|
50
|
+
project(#{@project_name})
|
51
|
+
include_directories(#{relative_vendor_path} comet-elements)
|
52
|
+
|
53
|
+
if (CMAKE_BUILD_TYPE EQUAL "DEBUG")
|
54
|
+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -cheerp-sourcemap=application.js.map -cheerp-sourcemap-standalone")
|
55
|
+
endif()
|
56
|
+
|
57
|
+
file(GLOB_RECURSE vendor_src #{relative_vendor_path}/*.cpp)
|
58
|
+
file(GLOB_RECURSE app_src app/*.cpp comet-elements/*.cpp)
|
59
|
+
|
60
|
+
add_executable(application ${vendor_src} ${app_src})
|
61
|
+
EOF
|
62
|
+
end unless @skip_project || (File.exists? "#{@project_dir}/CMakeLists.txt")
|
data/bin/comet-web
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
@output_path = "public"
|
5
|
+
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.on "-o PATH", "--output=PATH" do |v| @output_path = v end
|
8
|
+
end.parse!
|
9
|
+
|
10
|
+
@output_path = File.expand_path @output_path
|
11
|
+
|
12
|
+
server = WEBrick::HTTPServer.new Port: 8000, DocumentRoot: @output_path
|
13
|
+
trap 'INT' do server.shutdown end
|
14
|
+
server.start
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'comet-html/parser-class'
|
2
|
+
require 'comet-html/parser-repeater'
|
3
|
+
require 'comet-html/parser-slot'
|
4
|
+
require 'comet-html/utils'
|
5
|
+
require 'comet-html/header-generator'
|
6
|
+
require 'comet-html/source-generator'
|
7
|
+
require 'nokogiri'
|
8
|
+
require 'pathname'
|
9
|
+
|
10
|
+
module Comet
|
11
|
+
class LoadError < StandardError
|
12
|
+
attr_reader :message
|
13
|
+
def initialize
|
14
|
+
@message = "Load error: #{message}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ParseError < StandardError
|
19
|
+
attr_reader :el, :message
|
20
|
+
|
21
|
+
def initialize el, message
|
22
|
+
@el = el
|
23
|
+
@message = message
|
24
|
+
end
|
25
|
+
|
26
|
+
def line
|
27
|
+
el.line
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class HtmlParseError < StandardError
|
32
|
+
attr_reader :message, :line
|
33
|
+
|
34
|
+
def initialize error
|
35
|
+
@message = error.message
|
36
|
+
@line = error.line
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Generator
|
41
|
+
def initialize output, input, file
|
42
|
+
@output = output
|
43
|
+
@input = input
|
44
|
+
@filepath = file
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_config config
|
48
|
+
@config = config
|
49
|
+
end
|
50
|
+
|
51
|
+
def relative_filepath
|
52
|
+
@filepath[@input.length..-1]
|
53
|
+
end
|
54
|
+
|
55
|
+
def compiled_header_path
|
56
|
+
@output + relative_filepath.delete_suffix(File.extname relative_filepath) + ".hpp"
|
57
|
+
end
|
58
|
+
|
59
|
+
def compiled_source_path
|
60
|
+
@output + relative_filepath.delete_suffix(File.extname relative_filepath) + ".cpp"
|
61
|
+
end
|
62
|
+
|
63
|
+
def append_classes_predeclaration
|
64
|
+
result = ""
|
65
|
+
Context.classes.each do |object|
|
66
|
+
next if object.should_skip?
|
67
|
+
result += " class #{object.typename};\n"
|
68
|
+
end
|
69
|
+
result
|
70
|
+
end
|
71
|
+
|
72
|
+
def load_includes head
|
73
|
+
head.css("include").each do |include_attribute|
|
74
|
+
unless include_attribute["require"].nil?
|
75
|
+
type = include_attribute["require"].to_s
|
76
|
+
tag = if include_attribute["tag-name"].nil?
|
77
|
+
parts = type.split("<")
|
78
|
+
parts[0].gsub! "::", "_"
|
79
|
+
parts.join("<").dasherize
|
80
|
+
else
|
81
|
+
include_attribute["tag-name"].to_s
|
82
|
+
end
|
83
|
+
Context.element_types[tag] = type
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def prepare_includes head
|
89
|
+
result = ""
|
90
|
+
included_paths = []
|
91
|
+
head.css("include").each do |include_attribute|
|
92
|
+
included_paths << include_attribute["src"].to_s
|
93
|
+
end
|
94
|
+
included_paths.uniq.each do |include_path|
|
95
|
+
result += "# include \"#{include_path}\"\n"
|
96
|
+
end
|
97
|
+
@config["elements"].each do |element_data|
|
98
|
+
if Context.referenced_types.include? element_data["require"]
|
99
|
+
result += "# include \"#{element_data["include"]}\"\n"
|
100
|
+
end
|
101
|
+
end if !@config.nil? && !@config["elements"].nil?
|
102
|
+
result
|
103
|
+
end
|
104
|
+
|
105
|
+
def html5_tags
|
106
|
+
["article", "aside", "details", "figcaption", "figure", "footer", "header", "main", "mark", "nav", "section", "summary", "time"]
|
107
|
+
end
|
108
|
+
|
109
|
+
def whitelisted_tags
|
110
|
+
["svg"] + (if @config.nil? then [] else @config["whitelisted-tags"] || [] end)
|
111
|
+
end
|
112
|
+
|
113
|
+
def internal_tags
|
114
|
+
["include", "attribute", "slot"]
|
115
|
+
end
|
116
|
+
|
117
|
+
def is_error_fatal? error
|
118
|
+
matches = error.message.match(/^[0-9]+:[0-9]+: ERROR: Tag (.+) invalid$/)
|
119
|
+
unless matches.nil?
|
120
|
+
tagName = matches[1]
|
121
|
+
return false if (internal_tags + html5_tags + whitelisted_tags).include? tagName
|
122
|
+
return (if Context.element_types[tagName].nil? then true else false end)
|
123
|
+
end
|
124
|
+
return false if error.message.end_with?("ERROR: htmlParseEntityRef: no name") ||
|
125
|
+
error.message.end_with?("ERROR: Expected a doctype token$")
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
129
|
+
def generate
|
130
|
+
src = File.read @filepath
|
131
|
+
src.gsub! /<template/i, "<html"
|
132
|
+
src.gsub! /<\/template/i, "</html>"
|
133
|
+
|
134
|
+
document = Nokogiri::HTML.parse(src) do |config| config.strict end
|
135
|
+
|
136
|
+
html = document.xpath("html").first
|
137
|
+
head = document.xpath("//head")
|
138
|
+
body = document.xpath("//body")
|
139
|
+
raise LoadError.new "could not load html template `#{@filepath}`" if html.nil?
|
140
|
+
raise LoadError.new "missing body element in `#{@filepath}`" if body.first.nil?
|
141
|
+
|
142
|
+
Context.reset
|
143
|
+
Context.filename = @filepath
|
144
|
+
if !@config.nil? && !@config["elements"].nil?
|
145
|
+
Context.load_global_element_types @config["elements"]
|
146
|
+
end
|
147
|
+
|
148
|
+
load_includes head
|
149
|
+
|
150
|
+
fatal_error = nil
|
151
|
+
document.errors.each do |error|
|
152
|
+
if is_error_fatal? error
|
153
|
+
puts "[comet-html] #{@filepath}:#{error.line}:#{error.column}: #{error.message}"
|
154
|
+
fatal_error ||= error
|
155
|
+
error_count += 1
|
156
|
+
end
|
157
|
+
end
|
158
|
+
raise HtmlParseError.new fatal_error unless fatal_error.nil?
|
159
|
+
|
160
|
+
main_element = Comet::Class.new body
|
161
|
+
main_element.typename = if html["classname"].nil?
|
162
|
+
File.basename(@filepath, ".html").to_s.camelize
|
163
|
+
else
|
164
|
+
html["classname"]
|
165
|
+
end
|
166
|
+
main_element.superclass = html["extends"] unless html["extends"].nil?
|
167
|
+
main_element.probe
|
168
|
+
|
169
|
+
main_element.inline_code = ""
|
170
|
+
head.css("script").each do |script|
|
171
|
+
main_element.inline_code += script.text.strip + "\n"
|
172
|
+
end
|
173
|
+
|
174
|
+
head.css("attribute").each do |attribute|
|
175
|
+
main_element.refs << (CppReference.new attribute, attribute["type"], attribute["name"], attribute["value"])
|
176
|
+
end
|
177
|
+
|
178
|
+
define_name = "__COMET_CUSTOM_ELEMENT_#{main_element.typename.upcase}__"
|
179
|
+
header_code = ""
|
180
|
+
source_code = ""
|
181
|
+
Context.classes.reverse.each do |object|
|
182
|
+
next if object.should_skip?
|
183
|
+
header_code += HeaderGenerator.new(object).generate + "\n"
|
184
|
+
source_code += SourceGenerator.new(object).generate + "\n"
|
185
|
+
end
|
186
|
+
|
187
|
+
includes_str = prepare_includes head
|
188
|
+
|
189
|
+
header = <<HEADER
|
190
|
+
#ifndef #{define_name}
|
191
|
+
# define #{define_name}
|
192
|
+
|
193
|
+
# include <comet/bindable.hpp>
|
194
|
+
# include <comet/repeater.hpp>
|
195
|
+
# include <comet/slot_element.hpp>
|
196
|
+
# include <comet/comment_element.hpp>
|
197
|
+
# include <comet/custom_element.hpp>
|
198
|
+
# include <comet/signal.hpp>
|
199
|
+
#{includes_str}
|
200
|
+
|
201
|
+
namespace HtmlTemplate
|
202
|
+
{
|
203
|
+
#{append_classes_predeclaration}
|
204
|
+
#{header_code}
|
205
|
+
}
|
206
|
+
|
207
|
+
#endif
|
208
|
+
HEADER
|
209
|
+
|
210
|
+
source = <<SOURCE
|
211
|
+
#include <comet/lexical_cast.hpp>
|
212
|
+
#include "#{compiled_header_path}"
|
213
|
+
|
214
|
+
#{source_code}
|
215
|
+
SOURCE
|
216
|
+
|
217
|
+
{ header: header, source: source }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module Comet
|
2
|
+
class HeaderGenerator
|
3
|
+
attr_reader :object, :source
|
4
|
+
|
5
|
+
def initialize object
|
6
|
+
@object = object
|
7
|
+
end
|
8
|
+
|
9
|
+
def indent
|
10
|
+
" "
|
11
|
+
end
|
12
|
+
|
13
|
+
def signaler_definition
|
14
|
+
return "" if object.implements_ibindable_view?
|
15
|
+
# Signaler def. Must be a reference if the object isn't the root object
|
16
|
+
signaler_type = "Comet::Signal<std::string>"
|
17
|
+
signaler_type += "&" unless object.parent.nil?
|
18
|
+
"#{signaler_type} signaler;"
|
19
|
+
end
|
20
|
+
|
21
|
+
def bound_attributes_definition
|
22
|
+
return "" if object.implements_ibindable_view?
|
23
|
+
"Comet::BoundAttributes bound_attributes;"
|
24
|
+
end
|
25
|
+
|
26
|
+
def generate_getters_setters
|
27
|
+
result = ""
|
28
|
+
object.refs.each do |ref|
|
29
|
+
is_ptr = ref.type.end_with? '*'
|
30
|
+
if ref.has_getter?
|
31
|
+
if is_ptr
|
32
|
+
result += indent + "#{ref.type} get_#{ref.name}() const { return #{ref.name}; }\n"
|
33
|
+
else
|
34
|
+
result += indent + "const #{ref.type}& get_#{ref.name}() const { return #{ref.name}; }\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
if ref.has_setter?
|
38
|
+
if is_ptr
|
39
|
+
result += indent + "virtual void set_#{ref.name}(#{ref.type} __v) { #{ref.name} = __v; }\n"
|
40
|
+
else
|
41
|
+
result += indent + "virtual void set_#{ref.name}(const #{ref.type}& __v) { #{ref.name} = __v; }\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
result
|
46
|
+
end
|
47
|
+
|
48
|
+
def generate_anchors
|
49
|
+
result = ""
|
50
|
+
anchor_count = 0
|
51
|
+
object.collect_children.each do |child|
|
52
|
+
if child.is_anchorable?
|
53
|
+
anchor_count += 1
|
54
|
+
child.anchor_name = "anchor_#{anchor_count}"
|
55
|
+
result += indent + "Comet::CommentElement #{child.anchor_name};\n"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
result
|
59
|
+
end
|
60
|
+
|
61
|
+
def friends_def
|
62
|
+
result = ""
|
63
|
+
object.context.classes.each do |klass|
|
64
|
+
result += indent + "friend class #{klass.typename};\n" unless klass == object
|
65
|
+
end
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def generate_properties
|
70
|
+
protected_properties_def = ""
|
71
|
+
public_properties_def = ""
|
72
|
+
private_properties_def = ""
|
73
|
+
if object.is_root?
|
74
|
+
protected_properties_def += indent + "#{object.typename}* root;\n"
|
75
|
+
else
|
76
|
+
public_properties_def += indent + "#{object.parent.typename}* parent;\n"
|
77
|
+
protected_properties_def += indent + "#{object.root.typename}* root;\n"
|
78
|
+
end
|
79
|
+
object.refs.each do |ref|
|
80
|
+
suffix = " = #{ref.default_value}" if ref.has_default_value?
|
81
|
+
if ref.is_explicit?
|
82
|
+
protected_properties_def += indent + "#{ref.type} #{ref.name}#{suffix};\n"
|
83
|
+
elsif ref.is_implicit?
|
84
|
+
private_properties_def += indent + "#{ref.type} #{ref.name}#{suffix};\n"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
## BEGIN Repeaters
|
88
|
+
object.repeaters.each do |repeater|
|
89
|
+
protected_properties_def += indent + "Comet::Repeater<#{repeater.list_type}, #{repeater.typename}> #{repeater.repeater_name};\n"
|
90
|
+
end
|
91
|
+
if object.class == Repeater
|
92
|
+
public_properties_def += indent + "#{object.value_type} #{object.value_name};\n"
|
93
|
+
end
|
94
|
+
## END Repeaters
|
95
|
+
## BEGIN SLOTS
|
96
|
+
# Slots emanate from the root object.
|
97
|
+
if object.is_root?
|
98
|
+
all_slots = object.slots
|
99
|
+
object.recursively_collect_children.each do |child|
|
100
|
+
all_slots += child.slots
|
101
|
+
end
|
102
|
+
all_slots.each do |slot|
|
103
|
+
public_properties_def += indent + "Comet::SlotElement #{slot.slot_ref};\n"
|
104
|
+
end
|
105
|
+
else
|
106
|
+
object.slots.each do |slot|
|
107
|
+
public_properties_def += indent + "Comet::SlotElement& #{slot.slot_ref};\n"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
## END SLOTS
|
111
|
+
[public_properties_def, protected_properties_def, private_properties_def]
|
112
|
+
end
|
113
|
+
|
114
|
+
def generate
|
115
|
+
anchors_def = generate_anchors
|
116
|
+
public_properties_def, protected_properties_def, private_properties_def = generate_properties
|
117
|
+
|
118
|
+
<<HEADER
|
119
|
+
class #{object.typename} : public #{object.superclass}
|
120
|
+
{
|
121
|
+
#{friends_def}
|
122
|
+
protected:
|
123
|
+
#{bound_attributes_definition}
|
124
|
+
#{protected_properties_def}
|
125
|
+
private:
|
126
|
+
#{anchors_def}
|
127
|
+
#{private_properties_def}
|
128
|
+
public:
|
129
|
+
#{signaler_definition}
|
130
|
+
#{public_properties_def}
|
131
|
+
|
132
|
+
#{object.constructor_decl}
|
133
|
+
virtual ~#{object.typename}() {}
|
134
|
+
|
135
|
+
void bind_attributes();
|
136
|
+
void trigger_binding_updates();
|
137
|
+
|
138
|
+
#{generate_getters_setters}
|
139
|
+
|
140
|
+
#{object.inline_code}
|
141
|
+
};
|
142
|
+
HEADER
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'comet-html/utils'
|
2
|
+
|
3
|
+
module Comet
|
4
|
+
class EventListener
|
5
|
+
attr_reader :el, :attribute_name, :code, :is_cpp
|
6
|
+
|
7
|
+
def initialize el, parent, key, value
|
8
|
+
@el = el
|
9
|
+
@parent = parent
|
10
|
+
@is_cpp = key.start_with?("cpp::")
|
11
|
+
@attribute_name = key.delete_suffix(".trigger")
|
12
|
+
@attribute_name = @attribute_name[5..-1] if is_cpp
|
13
|
+
@code = value
|
14
|
+
|
15
|
+
if @parent.find_reference_for(el).nil?
|
16
|
+
@parent.refs << (Reference.new(el, @parent))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Binding
|
22
|
+
attr_reader :el, :attribute_name, :is_cpp, :bind_mode, :code
|
23
|
+
|
24
|
+
def initialize el, parent, key, value
|
25
|
+
@el = el
|
26
|
+
@parent = parent
|
27
|
+
|
28
|
+
@attribute_name = key.delete_suffix(".bind")
|
29
|
+
@is_cpp = attribute_name.start_with?("cpp::")
|
30
|
+
@attribute_name = attribute_name[5..-1] if is_cpp
|
31
|
+
@code, @bind_mode = extract_bind_mode_from value
|
32
|
+
|
33
|
+
if @parent.find_reference_for(el).nil?
|
34
|
+
@parent.refs << (Reference.new(el, @parent))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def binds_to_cpp_property?
|
39
|
+
@is_cpp
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|