summaryrefslogtreecommitdiff
path: root/lib/gitlab/changelog/template/context.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/changelog/template/context.rb')
-rw-r--r--lib/gitlab/changelog/template/context.rb70
1 files changed, 70 insertions, 0 deletions
diff --git a/lib/gitlab/changelog/template/context.rb b/lib/gitlab/changelog/template/context.rb
new file mode 100644
index 00000000000..8a0796d767e
--- /dev/null
+++ b/lib/gitlab/changelog/template/context.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Changelog
+ module Template
+ # Context is used to provide a binding/context to ERB templates used for
+ # rendering changelogs.
+ #
+ # This class extends BasicObject so that we only expose the bare minimum
+ # needed to render the ERB template.
+ class Context < BasicObject
+ MAX_NESTED_LOOPS = 4
+
+ def initialize(variables)
+ @variables = variables
+ @loop_nesting = 0
+ end
+
+ def get_binding
+ ::Kernel.binding
+ end
+
+ def each(value, &block)
+ max = MAX_NESTED_LOOPS
+
+ if @loop_nesting == max
+ ::Kernel.raise(
+ ::Template::TemplateError.new("You can only nest up to #{max} loops")
+ )
+ end
+
+ @loop_nesting += 1
+ result = value.each(&block) if value.respond_to?(:each)
+ @loop_nesting -= 1
+
+ result
+ end
+
+ # rubocop: disable Style/TrivialAccessors
+ def variables
+ @variables
+ end
+ # rubocop: enable Style/TrivialAccessors
+
+ def read(source, *steps)
+ current = source
+
+ steps.each do |step|
+ case current
+ when ::Hash
+ current = current[step]
+ when ::Array
+ return '' unless step.is_a?(::Integer)
+
+ current = current[step]
+ else
+ break
+ end
+ end
+
+ current
+ end
+
+ def truthy?(value)
+ value.respond_to?(:any?) ? value.any? : !!value
+ end
+ end
+ end
+ end
+end