app_archetype 1.2.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.
- checksums.yaml +7 -0
- data/.doxie.json +25 -0
- data/.github/workflows/build.yml +25 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +35 -0
- data/.ruby-version +1 -0
- data/CONTRIBUTING.md +51 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +172 -0
- data/LICENSE +21 -0
- data/README.md +138 -0
- data/Rakefile +19 -0
- data/app_archetype.gemspec +39 -0
- data/bin/archetype +20 -0
- data/lib/app_archetype.rb +14 -0
- data/lib/app_archetype/cli.rb +204 -0
- data/lib/app_archetype/cli/presenters.rb +106 -0
- data/lib/app_archetype/cli/prompts.rb +152 -0
- data/lib/app_archetype/generators.rb +95 -0
- data/lib/app_archetype/logger.rb +69 -0
- data/lib/app_archetype/renderer.rb +116 -0
- data/lib/app_archetype/template.rb +12 -0
- data/lib/app_archetype/template/helpers.rb +216 -0
- data/lib/app_archetype/template/manifest.rb +193 -0
- data/lib/app_archetype/template/plan.rb +172 -0
- data/lib/app_archetype/template/source.rb +39 -0
- data/lib/app_archetype/template/variable.rb +237 -0
- data/lib/app_archetype/template/variable_manager.rb +75 -0
- data/lib/app_archetype/template_manager.rb +113 -0
- data/lib/app_archetype/version.rb +6 -0
- data/lib/core_ext/string.rb +67 -0
- data/spec/app_archetype/cli/presenters_spec.rb +99 -0
- data/spec/app_archetype/cli/prompts_spec.rb +292 -0
- data/spec/app_archetype/cli_spec.rb +132 -0
- data/spec/app_archetype/generators_spec.rb +119 -0
- data/spec/app_archetype/logger_spec.rb +86 -0
- data/spec/app_archetype/renderer_spec.rb +291 -0
- data/spec/app_archetype/template/helpers_spec.rb +251 -0
- data/spec/app_archetype/template/manifest_spec.rb +245 -0
- data/spec/app_archetype/template/plan_spec.rb +191 -0
- data/spec/app_archetype/template/source_spec.rb +60 -0
- data/spec/app_archetype/template/variable_manager_spec.rb +103 -0
- data/spec/app_archetype/template/variable_spec.rb +245 -0
- data/spec/app_archetype/template_manager_spec.rb +221 -0
- data/spec/core_ext/string_spec.rb +143 -0
- data/spec/spec_helper.rb +29 -0
- metadata +370 -0
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'json-schema'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'jsonnet'
|
4
|
+
|
5
|
+
module AppArchetype
|
6
|
+
module Template
|
7
|
+
# Manifest is a description of an archetype
|
8
|
+
class Manifest
|
9
|
+
##
|
10
|
+
# Minimum supported archetype version
|
11
|
+
#
|
12
|
+
MIN_ARCHETYPE_VERSION = '1.0.0'.freeze
|
13
|
+
|
14
|
+
##
|
15
|
+
# Manifest JSON schema
|
16
|
+
#
|
17
|
+
SCHEMA = {
|
18
|
+
type: 'object',
|
19
|
+
required: %w[name version metadata variables],
|
20
|
+
|
21
|
+
properties: {
|
22
|
+
name: {
|
23
|
+
type: 'string'
|
24
|
+
},
|
25
|
+
version: {
|
26
|
+
type: 'string'
|
27
|
+
},
|
28
|
+
metadata: {
|
29
|
+
type: 'object',
|
30
|
+
required: %w[app_archetype],
|
31
|
+
|
32
|
+
properties: {
|
33
|
+
app_archetype: {
|
34
|
+
type: 'object',
|
35
|
+
required: %w[version]
|
36
|
+
}
|
37
|
+
}
|
38
|
+
},
|
39
|
+
variables: {
|
40
|
+
type: 'object'
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}.freeze
|
44
|
+
|
45
|
+
class <<self
|
46
|
+
##
|
47
|
+
# Creates a [AppArchetype::Template] from a manifest json so long as the
|
48
|
+
# manifest is compatible with this version of AppArchetype.
|
49
|
+
#
|
50
|
+
# @param [String] file_path
|
51
|
+
#
|
52
|
+
def new_from_file(file_path)
|
53
|
+
manifest = Jsonnet.evaluate(
|
54
|
+
File.read(file_path)
|
55
|
+
)
|
56
|
+
|
57
|
+
if incompatible?(manifest)
|
58
|
+
raise 'provided manifest is invalid or incompatible with '\
|
59
|
+
'this version of app archetype'
|
60
|
+
end
|
61
|
+
|
62
|
+
new(
|
63
|
+
file_path,
|
64
|
+
manifest
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Incompatible returns true if the current manifest is not compatible
|
70
|
+
# with this version of AppArchetype.
|
71
|
+
#
|
72
|
+
# A manifest is not compatible if it was created with a version greater
|
73
|
+
# than this the installed version.
|
74
|
+
#
|
75
|
+
# @param [Hash] manifest
|
76
|
+
#
|
77
|
+
# @return [Boolean]
|
78
|
+
#
|
79
|
+
def incompatible?(manifest)
|
80
|
+
manifest_version = manifest['metadata']['app_archetype']['version']
|
81
|
+
return true if manifest_version < MIN_ARCHETYPE_VERSION
|
82
|
+
return true if manifest_version > AppArchetype::VERSION
|
83
|
+
rescue NoMethodError
|
84
|
+
true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
attr_reader :path, :data, :variables
|
89
|
+
|
90
|
+
##
|
91
|
+
# Creates a manifest and memoizes the manifest data hash as a Hashe::Map
|
92
|
+
#
|
93
|
+
# On initialize the manifest variables are retrieved and memoized for use
|
94
|
+
# in rendering the templates.
|
95
|
+
#
|
96
|
+
# @param [String] path
|
97
|
+
# @param [Hash] data
|
98
|
+
#
|
99
|
+
def initialize(path, data)
|
100
|
+
@path = path
|
101
|
+
@data = OpenStruct.new(data)
|
102
|
+
@variables = AppArchetype::Template::VariableManager
|
103
|
+
.new(@data.variables)
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Manifest name getter
|
108
|
+
#
|
109
|
+
# @return [String]
|
110
|
+
#
|
111
|
+
def name
|
112
|
+
@data.name
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Manifest version getter
|
117
|
+
#
|
118
|
+
# @return [String]
|
119
|
+
#
|
120
|
+
def version
|
121
|
+
@data.version
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Manifest metadata getter
|
126
|
+
#
|
127
|
+
# @return [String]
|
128
|
+
#
|
129
|
+
def metadata
|
130
|
+
@data.metadata
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Parent path of the manifest (working directory)
|
135
|
+
#
|
136
|
+
# @return [String]
|
137
|
+
def parent_path
|
138
|
+
File.dirname(@path)
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Template files path
|
143
|
+
#
|
144
|
+
# @return [String]
|
145
|
+
#
|
146
|
+
def template_path
|
147
|
+
File.join(parent_path, 'template')
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# Loads the template that is adjacent to the manifest.json or
|
152
|
+
# manifest.jsonnet file.
|
153
|
+
#
|
154
|
+
# If the template cannot be found, a RuntimeError explaining that
|
155
|
+
# the template cannot
|
156
|
+
# be found is raised.
|
157
|
+
#
|
158
|
+
# Loaded template is memoized for the current session.
|
159
|
+
#
|
160
|
+
# @return [AppArchetype::Template::Source]
|
161
|
+
def template
|
162
|
+
unless File.exist?(template_path)
|
163
|
+
raise "cannot find template for manifest #{name}"
|
164
|
+
end
|
165
|
+
|
166
|
+
@template ||= AppArchetype::Template::Source.new(template_path)
|
167
|
+
@template
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# Runs a schema validation on the given manifest to determine whether
|
172
|
+
# the schema is valid. Returns an array of validation messages.
|
173
|
+
#
|
174
|
+
# @return [Array]
|
175
|
+
def validate
|
176
|
+
JSON::Validator.fully_validate(
|
177
|
+
SCHEMA,
|
178
|
+
@data.to_h.to_json,
|
179
|
+
strict: true
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
##
|
184
|
+
# Returns true if manifest is valid
|
185
|
+
#
|
186
|
+
# @return [Boolean]
|
187
|
+
#
|
188
|
+
def valid?
|
189
|
+
validate.empty?
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'ruby-handlebars'
|
2
|
+
require_relative '../../core_ext/string'
|
3
|
+
|
4
|
+
module AppArchetype
|
5
|
+
module Template
|
6
|
+
# Plan builds an in memory representation of template output
|
7
|
+
class Plan
|
8
|
+
attr_reader :template, :destination_path, :files, :variables
|
9
|
+
|
10
|
+
##
|
11
|
+
# Creates a new plan from given source and variables.
|
12
|
+
#
|
13
|
+
# @param [AppArchetype::Template::Source] template
|
14
|
+
# @param [AppArchetype::Template::VariableManager] variables
|
15
|
+
# @param [String] destination_path
|
16
|
+
# @param [Boolean] overwrite
|
17
|
+
#
|
18
|
+
def initialize(
|
19
|
+
template,
|
20
|
+
variables,
|
21
|
+
destination_path: nil,
|
22
|
+
overwrite: false
|
23
|
+
)
|
24
|
+
@template = template
|
25
|
+
@destination_path = destination_path
|
26
|
+
@files = []
|
27
|
+
@variables = variables
|
28
|
+
@overwrite = overwrite
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Devise builds an in memory representation of what needs to be done to
|
33
|
+
# render the template.
|
34
|
+
#
|
35
|
+
# When the destination path does not exist - a RuntimeError is raised -
|
36
|
+
# however at this stage we should always have a destination path to
|
37
|
+
# render to.
|
38
|
+
#
|
39
|
+
def devise
|
40
|
+
raise 'destination path does not exist' unless destination_exist?
|
41
|
+
|
42
|
+
@template.files.each do |file|
|
43
|
+
@files << OutputFile.new(
|
44
|
+
file,
|
45
|
+
render_dest_file_path(file)
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Execute will render the plan to disk
|
52
|
+
#
|
53
|
+
def execute
|
54
|
+
renderer = Renderer.new(
|
55
|
+
self,
|
56
|
+
@overwrite
|
57
|
+
)
|
58
|
+
|
59
|
+
renderer.render
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Check for whether the destination exists
|
64
|
+
#
|
65
|
+
# @return [Boolean]
|
66
|
+
def destination_exist?
|
67
|
+
return false unless @destination_path
|
68
|
+
|
69
|
+
File.exist?(
|
70
|
+
File.dirname(@destination_path)
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Determines what the destination file path is going to be by taking
|
76
|
+
# the source path, subbing the template path and then joining it
|
77
|
+
# with the specified destination path.
|
78
|
+
#
|
79
|
+
# Calls render path to handle any handlebars moustaches included within
|
80
|
+
# the file name.
|
81
|
+
#
|
82
|
+
# @param [String] source_path
|
83
|
+
#
|
84
|
+
# @return [String]
|
85
|
+
def render_dest_file_path(source_path)
|
86
|
+
rel_path = render_path(
|
87
|
+
source_path.gsub(@template.path, '')
|
88
|
+
)
|
89
|
+
|
90
|
+
File.join(@destination_path, rel_path)
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Renders template variables into any moustaches included in the filename
|
95
|
+
#
|
96
|
+
# This permits us to have variable file names as well as variable file
|
97
|
+
# content.
|
98
|
+
#
|
99
|
+
# @param [String] path
|
100
|
+
#
|
101
|
+
# @return [String]
|
102
|
+
#
|
103
|
+
def render_path(path)
|
104
|
+
hbs = Handlebars::Handlebars.new
|
105
|
+
hbs.compile(path).call(@variables.to_h)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# OutputFile represents a plan action, in other words holds a reference
|
110
|
+
# to a source file, and what the output is likely to be
|
111
|
+
class OutputFile
|
112
|
+
attr_reader :source_file_path, :path
|
113
|
+
|
114
|
+
##
|
115
|
+
# Creates an output file
|
116
|
+
#
|
117
|
+
# @param [String] source_file_path
|
118
|
+
# @param [String] path
|
119
|
+
#
|
120
|
+
def initialize(source_file_path, path)
|
121
|
+
@source_file_path = source_file_path
|
122
|
+
@path = path
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Evaluates whether the source file is a directory
|
127
|
+
#
|
128
|
+
# @return [Boolean]
|
129
|
+
#
|
130
|
+
def source_directory?
|
131
|
+
File.directory?(@source_file_path)
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Evaluates whether the source file is a erb template
|
136
|
+
#
|
137
|
+
# @return [Boolean]
|
138
|
+
#
|
139
|
+
def source_erb?
|
140
|
+
File.extname(@source_file_path) == '.erb'
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Evaluates whether the source file is a handlebars template
|
145
|
+
#
|
146
|
+
# @return [Boolean]
|
147
|
+
#
|
148
|
+
def source_hbs?
|
149
|
+
File.extname(@source_file_path) == '.hbs'
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Evaluates whether the source file is a file as opposed to
|
154
|
+
# being a directory.
|
155
|
+
#
|
156
|
+
# @return [Boolean]
|
157
|
+
#
|
158
|
+
def source_file?
|
159
|
+
File.file?(@source_file_path)
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# Evaluates whether the source file actually exists
|
164
|
+
#
|
165
|
+
# @return [Boolean]
|
166
|
+
#
|
167
|
+
def exist?
|
168
|
+
File.exist?(@path)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module AppArchetype
|
2
|
+
module Template
|
3
|
+
# Source is an in memory representation of a template source
|
4
|
+
class Source
|
5
|
+
attr_reader :path, :files
|
6
|
+
|
7
|
+
##
|
8
|
+
# Creates a templatte source from path and initializes file array.
|
9
|
+
#
|
10
|
+
# @param [String] path
|
11
|
+
#
|
12
|
+
def initialize(path)
|
13
|
+
@path = path
|
14
|
+
@files = []
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Loads template files into memory. Will raise a RuntimeError if
|
19
|
+
# by the time we're loading the source no longer exists.
|
20
|
+
#
|
21
|
+
def load
|
22
|
+
raise 'template source does not exist' unless exist?
|
23
|
+
|
24
|
+
Dir.glob(File.join(@path, '**', '*')).each do |file|
|
25
|
+
@files << file
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Evaluates whether template source still exists.
|
31
|
+
#
|
32
|
+
# @return [Boolean]
|
33
|
+
#
|
34
|
+
def exist?
|
35
|
+
File.exist?(@path)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module AppArchetype
|
5
|
+
module Template
|
6
|
+
# Variable is a class representing a single variable
|
7
|
+
class Variable
|
8
|
+
##
|
9
|
+
# Default variable type (String)
|
10
|
+
#
|
11
|
+
DEFAULT_TYPE = 'string'.freeze
|
12
|
+
|
13
|
+
##
|
14
|
+
# Default value map
|
15
|
+
#
|
16
|
+
DEFAULT_VALUES = {
|
17
|
+
'string' => '',
|
18
|
+
'boolean' => false,
|
19
|
+
'integer' => 0
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
##
|
23
|
+
# String validation function. Ensures given input
|
24
|
+
# is indeed a string.
|
25
|
+
#
|
26
|
+
# @param [Object] input
|
27
|
+
#
|
28
|
+
# @return [Boolean]
|
29
|
+
#
|
30
|
+
STRING_VALIDATOR = lambda do |input|
|
31
|
+
input.is_a?(String)
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Boolean validation function. Ensures given input
|
36
|
+
# is a boolean.
|
37
|
+
#
|
38
|
+
# @param [Object] input
|
39
|
+
#
|
40
|
+
# @return [Boolean]
|
41
|
+
#
|
42
|
+
BOOLEAN_VALIDATOR = lambda do |input|
|
43
|
+
[true, false, 'true', 'false'].include?(input)
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Integer validation function. Ensures given input is
|
48
|
+
# an integer.
|
49
|
+
#
|
50
|
+
# @param [Object] input
|
51
|
+
#
|
52
|
+
# @return [Boolean]
|
53
|
+
#
|
54
|
+
INTEGER_VALIDATOR = lambda do |input|
|
55
|
+
input != '0' && input.to_i != 0
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Maps type to validation function
|
60
|
+
#
|
61
|
+
VALIDATORS = {
|
62
|
+
'string' => STRING_VALIDATOR,
|
63
|
+
'boolean' => BOOLEAN_VALIDATOR,
|
64
|
+
'integer' => INTEGER_VALIDATOR
|
65
|
+
}.freeze
|
66
|
+
|
67
|
+
##
|
68
|
+
# Default validation function (string validator)
|
69
|
+
#
|
70
|
+
DEFAULT_VALIDATOR = STRING_VALIDATOR
|
71
|
+
|
72
|
+
attr_reader :name
|
73
|
+
|
74
|
+
def initialize(name, spec)
|
75
|
+
@name = name
|
76
|
+
@spec = OpenStruct.new(spec)
|
77
|
+
@value = @spec.value
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Sets value of variable so long as it's valid.
|
82
|
+
#
|
83
|
+
# A runtime error will be raised if the valdiation
|
84
|
+
# fails for the given value.
|
85
|
+
#
|
86
|
+
# Has a side effect of setting @value instance variable
|
87
|
+
#
|
88
|
+
# @param [Object] value
|
89
|
+
def set!(value)
|
90
|
+
raise 'invalid value' unless valid?(value)
|
91
|
+
|
92
|
+
@value = value
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Returns default value for the variable.
|
97
|
+
#
|
98
|
+
# In the event the manifest does not specify a default
|
99
|
+
# one will be picked from the DEFAULT_VALUES map based on
|
100
|
+
# the variable's type.
|
101
|
+
#
|
102
|
+
# @return [Object]
|
103
|
+
#
|
104
|
+
def default
|
105
|
+
return DEFAULT_VALUES[type] unless @spec.default
|
106
|
+
|
107
|
+
@spec.default
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Returns variable description.
|
112
|
+
#
|
113
|
+
# In the event the manifest does not specify a description
|
114
|
+
# an empty string will be returned.
|
115
|
+
#
|
116
|
+
# @return [String]
|
117
|
+
#
|
118
|
+
def description
|
119
|
+
return '' unless @spec.description
|
120
|
+
|
121
|
+
@spec.description
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Returns variable type.
|
126
|
+
#
|
127
|
+
# In the event the manifest does not specify a type, the
|
128
|
+
# default type of String will be returned.
|
129
|
+
#
|
130
|
+
# @return [String]
|
131
|
+
#
|
132
|
+
def type
|
133
|
+
return DEFAULT_TYPE unless @spec.type
|
134
|
+
|
135
|
+
@spec.type
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Returns variable value.
|
140
|
+
#
|
141
|
+
# If the value has not been set (i.e. overridden) then the
|
142
|
+
# default value will be returned.
|
143
|
+
#
|
144
|
+
# Values set beginning with `#` are passed into the helpers
|
145
|
+
# class and evaluated as functions. That permits the manifest
|
146
|
+
# to use string helpers as values from the manifest.
|
147
|
+
#
|
148
|
+
# Function calls must be in the format `#method_name,arg1,arg2`
|
149
|
+
# for example to call the join function `#join,.,biggerconcept,com`
|
150
|
+
# will result in `biggerconcept.com` becoming the value.
|
151
|
+
#
|
152
|
+
# @return [String]
|
153
|
+
#
|
154
|
+
def value
|
155
|
+
return default if @value.nil?
|
156
|
+
return call_helper if method?
|
157
|
+
|
158
|
+
@value
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Returns true if value has been set
|
163
|
+
#
|
164
|
+
# @return [Boolean]
|
165
|
+
def value?
|
166
|
+
!@value.nil?
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Retrieves the appropriate validator function basedd on the
|
171
|
+
# specified type.
|
172
|
+
#
|
173
|
+
# If a type is not set then a string validator function is
|
174
|
+
# returned by default
|
175
|
+
#
|
176
|
+
# @return [Proc]
|
177
|
+
#
|
178
|
+
def validator
|
179
|
+
validator = VALIDATORS[@spec.type]
|
180
|
+
validator ||= DEFAULT_VALIDATOR
|
181
|
+
|
182
|
+
validator
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Returns true if the value input is valid.
|
187
|
+
#
|
188
|
+
# @param [String] input
|
189
|
+
#
|
190
|
+
# @return [Boolean]
|
191
|
+
#
|
192
|
+
def valid?(input)
|
193
|
+
validator.call(input)
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
# Returns an object which extends helpers module.
|
199
|
+
#
|
200
|
+
# This is used for calling helper functions
|
201
|
+
def helpers
|
202
|
+
Object
|
203
|
+
.new
|
204
|
+
.extend(AppArchetype::Template::Helpers)
|
205
|
+
end
|
206
|
+
|
207
|
+
# Returns true if variable value begins with `#` this
|
208
|
+
# indicates the variable value has been set to a function
|
209
|
+
def method?
|
210
|
+
return false unless @value.is_a?(String)
|
211
|
+
|
212
|
+
@value[0, 1] == '#'
|
213
|
+
end
|
214
|
+
|
215
|
+
# Calls a helper function to generate a value
|
216
|
+
def call_helper
|
217
|
+
method = deserialize_method(@value)
|
218
|
+
helpers.send(method.name, *method.args)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Creates a struct representing a method call to be made
|
222
|
+
# to resolve a variable value
|
223
|
+
def deserialize_method(method)
|
224
|
+
method = method.delete('#')
|
225
|
+
parts = method.split(',')
|
226
|
+
name = parts.shift
|
227
|
+
|
228
|
+
args = parts || []
|
229
|
+
|
230
|
+
OpenStruct.new(
|
231
|
+
name: name.to_sym,
|
232
|
+
args: args
|
233
|
+
)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|