Skip to content

Commit 39a657a

Browse files
authored
Merge pull request #113 from aminya/customcode
Custom code
2 parents 7143d74 + bf325af commit 39a657a

File tree

15 files changed

+582
-109
lines changed

15 files changed

+582
-109
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,23 @@ Pkg.add("AcuteML")
1818
```julia
1919
using AcuteML
2020
```
21+
2122
# Documentation
2223
Click on the badge: [![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://aminya.github.io/AcuteML.jl/dev)
2324

2425
See [Type Definition](https://aminya.github.io/AcuteML.jl/dev/#Main-macro-and-I/O-1) for a comprehensive introduction to syntax. You can use `@aml` macro to define a Julia type, and then the package automatically creates a xml or html associated with the defined type.
2526

27+
# Readme Content
28+
- [Installation and Usage](#installation-and-usage)
29+
- [Documentation](#documentation)
30+
- [Example - Simple](#example---simple)
31+
- [Example - Struct Definition](#example---struct-definition)
32+
- [Example - Creator](#example---creator)
33+
- [Example - Extractor](#example---extractor)
34+
- [Templating](#templating)
35+
- [Example - Template Rendering using Functions](#example---template-rendering-using-functions)
36+
- [Example - Template Rendering using Files](#example---template-rendering-using-files)
37+
2638
# Example - Simple
2739
```julia
2840
using AcuteML
@@ -41,7 +53,7 @@ d = html(body = b)
4153
```
4254
```html
4355
julia> pprint(d)
44-
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
56+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
4557
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
4658
<html>
4759
<body>

deps/SnoopCompile/precompile/precompile_AcuteML.jl

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,24 @@ function _precompile_()
22
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
33
isdefined(AcuteML, Symbol("#8#17")) && precompile(Tuple{getfield(AcuteML, Symbol("#8#17")),Nothing})
44
precompile(Tuple{Core.kwftype(typeof(AcuteML.render2file)),NamedTuple{(:id, :age, :field, :GPA, :courses),Tuple{Int64,Int64,String,Float64,Array{String,1}}},typeof(render2file),String,Bool})
5-
precompile(Tuple{typeof(AcuteML.aml_create),Expr,Array{Union{Expr, Symbol},1},Array{Any,1},Array{Union{Expr, Symbol, Type},1},Array{Union{Expr, Symbol},1},Array{Union{Missing, String},1},Array{Union{Missing, Function, Symbol},1},Array{Union{Missing, Type},1},String,Type{T} where T,Array{Union{Missing, Function, Symbol},0},Bool,Symbol})
5+
precompile(Tuple{typeof(AcuteML.aml_create),Expr,Array{Union{Expr, Symbol},1},Array{Any,1},Array{Union{Expr, Symbol, Type},1},Array{Union{Expr, Symbol},1},Array{Union{Missing, String},1},Array{Union{Missing, Function, Symbol},1},Array{Union{Missing, Type},1},String,Type{T} where T,Array{Union{Missing, Function, Symbol},0},Bool,Array{Union{Nothing, Expr},1},Array{Union{Nothing, Expr},1},Array{Union{Nothing, Expr},1},Symbol})
66
precompile(Tuple{typeof(AcuteML.aml_parse),Expr})
7-
precompile(Tuple{typeof(AcuteML.get_arg_xmlcreator),Bool,Expr,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
8-
precompile(Tuple{typeof(AcuteML.get_arg_xmlcreator),Bool,Symbol,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
9-
precompile(Tuple{typeof(AcuteML.get_arg_xmlcreator),Bool,Symbol,Symbol,String,Type{T} where T,Symbol,QuoteNode,Expr})
10-
precompile(Tuple{typeof(AcuteML.get_arg_xmlcreator),Bool,Type{T} where T,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
11-
precompile(Tuple{typeof(AcuteML.get_arg_xmlextractor),Bool,Expr,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
12-
precompile(Tuple{typeof(AcuteML.get_arg_xmlextractor),Bool,Symbol,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
13-
precompile(Tuple{typeof(AcuteML.get_arg_xmlextractor),Bool,Symbol,Symbol,String,Type{T} where T,Symbol,QuoteNode,Expr})
14-
precompile(Tuple{typeof(AcuteML.get_arg_xmlextractor),Bool,Type{T} where T,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
15-
precompile(Tuple{typeof(AcuteML.get_arg_xmludpater),Bool,Expr,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
16-
precompile(Tuple{typeof(AcuteML.get_arg_xmludpater),Bool,Symbol,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
17-
precompile(Tuple{typeof(AcuteML.get_arg_xmludpater),Bool,Symbol,Symbol,String,Type{T} where T,Symbol,QuoteNode,Expr})
18-
precompile(Tuple{typeof(AcuteML.get_arg_xmludpater),Bool,Type{T} where T,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
7+
precompile(Tuple{typeof(AcuteML.get_arg_xmlcreator),Nothing,Bool,Expr,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
8+
precompile(Tuple{typeof(AcuteML.get_arg_xmlcreator),Nothing,Bool,Symbol,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
9+
precompile(Tuple{typeof(AcuteML.get_arg_xmlcreator),Nothing,Bool,Symbol,Symbol,String,Type{T} where T,Symbol,QuoteNode,Expr})
10+
precompile(Tuple{typeof(AcuteML.get_arg_xmlcreator),Nothing,Bool,Type{T} where T,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
11+
precompile(Tuple{typeof(AcuteML.get_arg_xmlextractor),Nothing,Bool,Expr,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
12+
precompile(Tuple{typeof(AcuteML.get_arg_xmlextractor),Nothing,Bool,Symbol,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
13+
precompile(Tuple{typeof(AcuteML.get_arg_xmlextractor),Nothing,Bool,Symbol,Symbol,String,Type{T} where T,Symbol,QuoteNode,Expr})
14+
precompile(Tuple{typeof(AcuteML.get_arg_xmlextractor),Nothing,Bool,Type{T} where T,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
15+
precompile(Tuple{typeof(AcuteML.get_arg_xmludpater),Nothing,Bool,Expr,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
16+
precompile(Tuple{typeof(AcuteML.get_arg_xmludpater),Nothing,Bool,Symbol,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
17+
precompile(Tuple{typeof(AcuteML.get_arg_xmludpater),Nothing,Bool,Symbol,Symbol,String,Type{T} where T,Symbol,QuoteNode,Expr})
18+
precompile(Tuple{typeof(AcuteML.get_arg_xmludpater),Nothing,Bool,Type{T} where T,Symbol,String,Type{T} where T,Missing,QuoteNode,Expr})
1919
precompile(Tuple{typeof(AcuteML.multiString),Array{String,1}})
2020
precompile(Tuple{typeof(AcuteML.multiString),Float64})
2121
precompile(Tuple{typeof(AcuteML.multiString),Int64})
2222
precompile(Tuple{typeof(AcuteML.multiString),String})
23-
precompile(Tuple{typeof(addelm!),Document,String,Nothing,Type{AbsAttribute}})
2423
precompile(Tuple{typeof(addelm!),Node,String,Array{Any,1},Type{AbsNormal}})
2524
precompile(Tuple{typeof(addelm!),Node,String,Array{Float64,1},Type{AbsNormal}})
2625
precompile(Tuple{typeof(addelm!),Node,String,Array{Int64,1},Type{AbsNormal}})

docs/src/customConstructors.md

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,117 @@
1-
# Custom Constructors - AcuteML Backend
2-
## Making a Type and constructor from scratch
1+
# Custom Constructors
2+
3+
## Adding Custom code to the structures
4+
5+
AcuteML introduces three `@creator`, `@extractor`, and `@updater` macros to be used inside `@aml` definition. The location of the macros specifies their location in the function. For example, putting `@creator` at the begining, adds the code to begining of creator function.
6+
7+
8+
- Put `@creator` inside `@aml` to add a custom code to the creator function (DOM creation when the struct is instanciated).
9+
10+
This macro only affects creation (not extraction/updating), but can be used in combination with other macros.
11+
12+
- Put `@extractor` inside `@aml` to add a custom code to the extractor function (DOM parsing when a html/xml text is used for instanciation of a struct).
13+
14+
This macro only affects creation (not creation/updating), but can be used in combination with other macros.
15+
16+
Be careful that setting struct fields using `@extractor` only changes the struct field and not the xml code.
17+
18+
- Put `@updater` inside `@aml` to add a custom code to the updater function (DOM updating after instanciation of a struct).
19+
20+
This macro only affects updating (not creation/extraction), but can be used in combination with other macros.
21+
22+
In the following example `IQ` and `average` are calculated automatically. Also, in the following example `log` is filled automatically (which doesn't have an associated xml element).
23+
24+
```julia
25+
using AcuteML
26+
# Definition
27+
@aml mutable struct Student "student"
28+
29+
# add custom code to the begining of creator function
30+
# the following automatically fills IQ based on the name
31+
@creator begin
32+
if occursin("smart", name)
33+
name = replace(name, "-smart" => "") # remove smart from name
34+
IQ = "smart"
35+
elseif occursin("genius", name)
36+
name = replace(name, "-genius" => "") # remove smart from name
37+
IQ = "genius"
38+
else
39+
error("Give a smart student.")
40+
end
41+
end
42+
43+
name::String, "~"
44+
GPA::Float64, "~"
45+
IQ::UN{String} = nothing, att"~" # default to nothing, but filled automatically by first @cretor macro
46+
# add custom code to the end of extractor function
47+
48+
log::UN{String} = nothing, "~"
49+
50+
@extractor begin
51+
if GPA > 4.0
52+
log = "A genius with a GPA of $GPA is found" # setting fields using @extractor only changes the field and not the xml code
53+
end
54+
end
55+
end
56+
57+
@aml mutable struct MathClass "math-class"
58+
@creator begin
59+
GPAsum = 0.0
60+
for student in students
61+
GPAsum = GPAsum + student.GPA
62+
end
63+
average = GPAsum / length(students) # fill average field
64+
end
65+
66+
students::Vector{Student}, "student"
67+
average::UN{Float64} = nothing, "average" # calculated automatically
68+
end
69+
70+
################################################################
71+
# Creation
72+
smarts = [Student(name = "Jack-smart", GPA = 2.0), Student(name = "Sara-genius", GPA = 5.0)]
73+
mathclass = MathClass(students = smarts)
74+
75+
mathclass.students[1].name # "Jack"
76+
mathclass.students[2].name # "Sara"
77+
mathclass.average # 3.5
78+
79+
pprint(mathclass)
80+
# <math-class>
81+
# <student IQ="smart">
82+
# <name>Jack</name>
83+
# <GPA>2.0</GPA>
84+
# </student>
85+
# <student IQ="genius">
86+
# <name>Sara</name>
87+
# <GPA>5.0</GPA>
88+
# </student>
89+
# <average>3.5</average>
90+
# </math-class>
91+
92+
################################################################
93+
# Extraction
94+
95+
xml = parsexml("""
96+
<math-class>
97+
<student>
98+
<name>Jack</name>
99+
<GPA>2.0</GPA>
100+
</student>
101+
<student>
102+
<name>Sara</name>
103+
<GPA>5.0</GPA>
104+
</student>
105+
<average>3.5</average>
106+
</math-class>
107+
""")
108+
109+
mathclass = MathClass(xml)
110+
111+
mathclass.students[2].log # "A genius with a GPA of 5.0 is found"
112+
```
113+
114+
## Making a Type and constructor from scratch using AcuteML Backend
3115

4116
You can use AcuteML utilities to define custom type constructors from scratch or to override `@aml` defined constructors.
5117

examples/customcode.jl

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using AcuteML
2+
# Definition
3+
@aml mutable struct Student "student"
4+
5+
# add custom code to the begining of creator function
6+
# the following automatically fills IQ based on the name
7+
@creator begin
8+
if occursin("smart", name)
9+
name = replace(name, "-smart" => "") # remove smart from name
10+
IQ = "smart"
11+
elseif occursin("genius", name)
12+
name = replace(name, "-genius" => "") # remove smart from name
13+
IQ = "genius"
14+
else
15+
error("Give a smart student.")
16+
end
17+
end
18+
19+
name::String, "~"
20+
GPA::Float64, "~"
21+
IQ::UN{String} = nothing, att"~" # default to nothing, but filled automatically by first @cretor macro
22+
# add custom code to the end of extractor function
23+
24+
log::UN{String} = nothing, "~"
25+
26+
@extractor begin
27+
if GPA > 4.0
28+
log = "A genius with a GPA of $GPA is found" # setting fields using @extractor only changes the field and not the xml code
29+
end
30+
end
31+
end
32+
33+
@aml mutable struct MathClass "math-class"
34+
@creator begin
35+
GPAsum = 0.0
36+
for student in students
37+
GPAsum = GPAsum + student.GPA
38+
end
39+
average = GPAsum / length(students) # fill average field
40+
end
41+
42+
students::Vector{Student}, "student"
43+
average::UN{Float64} = nothing, "average" # calculated automatically
44+
end
45+
46+
################################################################
47+
# Creation
48+
smarts = [Student(name = "Jack-smart", GPA = 2.0), Student(name = "Sara-genius", GPA = 5.0)]
49+
mathclass = MathClass(students = smarts)
50+
51+
mathclass.students[1].name # "Jack"
52+
mathclass.students[2].name # "Sara"
53+
mathclass.average # 3.5
54+
55+
pprint(mathclass)
56+
# <math-class>
57+
# <student IQ="smart">
58+
# <name>Jack</name>
59+
# <GPA>2.0</GPA>
60+
# </student>
61+
# <student IQ="genius">
62+
# <name>Sara</name>
63+
# <GPA>5.0</GPA>
64+
# </student>
65+
# <average>3.5</average>
66+
# </math-class>
67+
68+
################################################################
69+
# Extraction
70+
71+
xml = parsexml("""
72+
<math-class>
73+
<student>
74+
<name>Jack</name>
75+
<GPA>2.0</GPA>
76+
</student>
77+
<student>
78+
<name>Sara</name>
79+
<GPA>5.0</GPA>
80+
</student>
81+
<average>3.5</average>
82+
</math-class>
83+
""")
84+
85+
mathclass = MathClass(xml)
86+
87+
mathclass.students[2].log # "A genius with a GPA of 5.0 is found"

src/@aml/@aml_create.jl

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ include("@aml_create/get_struct_xml_.jl")
44
"""
55
@aml creator function
66
"""
7-
function aml_create(expr::Expr, args_param, args_defaultvalue, args_type, args_var, args_name, args_function, args_literaltype, struct_name, struct_nodetype, struct_function, is_struct_mutable, T)
7+
function aml_create(expr::Expr, args_param, args_defaultvalue, args_type, args_var, args_name, args_function, args_literaltype, struct_name, struct_nodetype, struct_function, is_struct_mutable, args_custom_creator, args_custom_extractor, args_custom_updater, T)
88

99
expr.head == :struct || error("Invalid usage of aml_create")
1010

@@ -26,6 +26,13 @@ function aml_create(expr::Expr, args_param, args_defaultvalue, args_type, args_v
2626
amlargs_defaultvalue = args_defaultvalue[isaml_args]
2727
amlargs_literaltype = args_literaltype[isaml_args]
2828
amlargs_type = args_type[isaml_args]
29+
push!(isaml_args, false) # separating end
30+
amlargs_custom_creator = args_custom_creator[isaml_args]
31+
custom_creator_end = args_custom_creator[end]
32+
amlargs_custom_extractor = args_custom_extractor[isaml_args]
33+
custom_extractor_end = args_custom_extractor[end]
34+
amlargs_custom_updater = args_custom_updater[isaml_args]
35+
custom_updater_end = args_custom_updater[end]
2936

3037
amlargs_num = length(amlargs_var)
3138

@@ -43,6 +50,9 @@ function aml_create(expr::Expr, args_param, args_defaultvalue, args_type, args_v
4350
argname = amlargs_name[iArg]
4451
argliteraltype = amlargs_literaltype[iArg]
4552
argfunction=amlargs_function[iArg]
53+
argcustomcreator = amlargs_custom_creator[iArg]
54+
argcustomextractor = amlargs_custom_extractor[iArg]
55+
argcustomupdater = amlargs_custom_updater[iArg]
4656
argsym=QuoteNode(argvar)
4757
##########################
4858
# call Expr - For mutability
@@ -53,12 +63,12 @@ function aml_create(expr::Expr, args_param, args_defaultvalue, args_type, args_v
5363

5464
inps = (has_arg_xmlchecker, argtype, argvar, argname, argliteraltype, argfunction, argsym, argvarcall)
5565

56-
args_xmlcreator[iArg]=get_arg_xmlcreator(inps...)
66+
args_xmlcreator[iArg]=get_arg_xmlcreator(argcustomcreator, inps...)
5767

58-
args_xmlextractor[iArg]=get_arg_xmlextractor(inps...)
68+
args_xmlextractor[iArg]=get_arg_xmlextractor(argcustomextractor, inps...)
5969

6070
if is_struct_mutable
61-
args_xmludpater[iArg] = get_arg_xmludpater(inps...)
71+
args_xmludpater[iArg] = get_arg_xmludpater(argcustomupdater, inps...)
6272
end
6373

6474
end # endfor
@@ -91,15 +101,15 @@ function aml_create(expr::Expr, args_param, args_defaultvalue, args_type, args_v
91101
struct_xmlchecker = get_struct_xmlchecker(struct_function, args_var)
92102

93103
# Creator
94-
struct_xmlcreator = get_struct_xmlcreator(S, amlargs_param, struct_xmlchecker, node_initializer, args_xmlcreator, args_var)
104+
struct_xmlcreator = get_struct_xmlcreator(S, amlargs_param, struct_xmlchecker, node_initializer, args_xmlcreator, args_var, custom_creator_end)
95105
# Extractor
96-
struct_xmlextractor = get_struct_xmlextractor(S, args_xmlextractor, struct_xmlchecker, args_var)
106+
struct_xmlextractor = get_struct_xmlextractor(S, args_xmlextractor, struct_xmlchecker, args_var, custom_extractor_end)
97107

98108
if iscurly
99109
# Creator
100-
struct_xmlcreator_curly = get_struct_xmlcreator(SQ, P, amlargs_param, struct_xmlchecker, node_initializer, args_xmlcreator, args_var)
110+
struct_xmlcreator_curly = get_struct_xmlcreator(SQ, P, amlargs_param, struct_xmlchecker, node_initializer, args_xmlcreator, args_var, custom_creator_end)
101111
# Extractor
102-
struct_xmlextractor_curly = get_struct_xmlextractor(SQ, P, args_xmlextractor, struct_xmlchecker, args_var)
112+
struct_xmlextractor_curly = get_struct_xmlextractor(SQ, P, args_xmlextractor, struct_xmlchecker, args_var, custom_extractor_end)
103113
else
104114
struct_xmlcreator_curly = nothing
105115
struct_xmlextractor_curly = nothing
@@ -110,7 +120,7 @@ function aml_create(expr::Expr, args_param, args_defaultvalue, args_type, args_v
110120
self_method = :( ($(esc(S)))(in::$(esc(S))) = $(esc(S))(in.aml) )
111121
pprint_method = :( AcuteML.pprint(in::$(esc(S))) = pprint(in.aml) )
112122

113-
struct_xmlupdater = get_struct_xmlupdater(is_struct_mutable, S, args_xmludpater, struct_function, args_varcall)
123+
struct_xmlupdater = get_struct_xmlupdater(is_struct_mutable, S, args_xmludpater, struct_function, args_varcall, custom_updater_end)
114124

115125
out = quote
116126
Base.@__doc__($(esc(struct_definition)))

0 commit comments

Comments
 (0)