archetype 1.0.0.alpha.2 → 1.0.0.alpha.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -3
  3. data/README.md +1 -1
  4. data/VERSION +1 -1
  5. data/lib/archetype.rb +4 -0
  6. data/lib/archetype/actions/migrate.rb +10 -0
  7. data/lib/archetype/extensions.rb +35 -1
  8. data/lib/archetype/functions/helpers.rb +8 -0
  9. data/lib/archetype/functions/styleguide_memoizer.rb +1 -1
  10. data/lib/archetype/sass_extensions/functions/environment.rb +1 -1
  11. data/lib/archetype/sass_extensions/functions/lists.rb +2 -1
  12. data/lib/archetype/sass_extensions/functions/styleguide.rb +45 -88
  13. data/lib/archetype/sass_extensions/functions/styleguide/components.rb +230 -1
  14. data/lib/archetype/sass_extensions/functions/styleguide/constants.rb +0 -1
  15. data/lib/archetype/sass_extensions/functions/styleguide/grammar.rb +66 -5
  16. data/lib/archetype/sass_extensions/functions/styleguide/helpers.rb +36 -1
  17. data/lib/archetype/sass_extensions/functions/styleguide/resolve.rb +12 -2
  18. data/lib/archetype/sass_extensions/functions/styleguide/styles.rb +6 -3
  19. data/lib/archetype/sass_extensions/functions/styleguide/themes.rb +2 -1
  20. data/lib/archetype/sass_extensions/functions/ui/glyphs.rb +1 -1
  21. data/lib/archetype/sass_extensions/functions/ui/scopes.rb +4 -4
  22. data/lib/archetype/sass_extensions/functions/util/debug.rb +1 -1
  23. data/lib/archetype/sass_extensions/functions/util/hacks.rb +4 -8
  24. data/lib/archetype/sass_extensions/functions/util/images.rb +11 -8
  25. data/lib/archetype/sass_extensions/functions/util/misc.rb +34 -1
  26. data/lib/archetype/sass_extensions/functions/util/spacing.rb +1 -1
  27. data/stylesheets/archetype/hacks/_hacks.scss +1 -1
  28. data/stylesheets/archetype/styleguide/_styleguide.scss +2 -0
  29. data/stylesheets/archetype/util/_styles.scss +165 -125
  30. data/stylesheets/archetype/util/_targeting.scss +62 -54
  31. data/templates/example/screen.scss +2 -0
  32. data/templates/project/manifest.rb +1 -1
  33. metadata +24 -12
@@ -20,7 +20,6 @@ module Archetype::SassExtensions::Styleguide
20
20
  MULTIMIXINS = %w(target-browser)
21
21
  # NOTE: these are no longer used/needed if you're using the map structures
22
22
  ADDITIVES = FALLBACKS + [DROP, INHERIT, STYLEGUIDE] + MULTIMIXINS
23
- @@archetype_styleguide_mutex = Mutex.new
24
23
  @@styleguide_themes ||= nil
25
24
  # :startdoc:
26
25
 
@@ -1,5 +1,35 @@
1
1
  module Archetype::SassExtensions::Styleguide
2
2
 
3
+ #
4
+ # exposes the grammar used when interpreting styleguide calls
5
+ #
6
+ # *Parameters*:
7
+ # - <tt>sentence</tt> {String|List} the sentence describing the component
8
+ # - <tt>theme</tt> {String} the theme to use
9
+ # - <tt>state</tt> {String} the name of a state to return
10
+ # *Returns*:
11
+ # - {Map} a map including the `identifier` and `modifiers`
12
+ def _styleguide_grammar(sentence, theme = nil, state = nil)
13
+ keys = ['identifier', 'modifiers', 'token']
14
+ id, modifiers, token = grammar(sentence, theme, state)
15
+
16
+ # if the id is empty, then it means that the sentence didn't contain a valid component id
17
+ # so we set everything to `null`
18
+ unless id
19
+ id = null
20
+ modifiers = null
21
+ # otherwise we ensure that we're sending back appropriate values
22
+ else
23
+ id = identifier(id)
24
+ modifiers = modifiers.empty? ? null : list(modifiers.map{|m| identifier(m)}, :space)
25
+ end
26
+
27
+ return Sass::Script::Value::Map.new({
28
+ identifier('identifier') => id,
29
+ identifier('modifiers') => modifiers
30
+ });
31
+ end
32
+
3
33
  private
4
34
 
5
35
  #
@@ -13,11 +43,28 @@ module Archetype::SassExtensions::Styleguide
13
43
  # - {Array} an array containing the identifer, modifiers, and a token
14
44
  #
15
45
  def grammar(sentence, theme = nil, state = nil)
46
+ _styleguide_debug "converting `#{sentence}` to grammar", :grammar
16
47
  theme = get_theme(theme)
17
48
  components = theme[:components]
18
49
  # get a list of valid ids
19
50
  styleguideIds = components.keys
20
- sentence = sentence.split if sentence.is_a? String
51
+
52
+ # convert the sentence to a string and then split into an array
53
+ # this ensures that all the pieces are treated as strings and not other primitive types (e.g. a list of strings in the middle of a sentence)
54
+ sentence = helpers.to_str(sentence).split
55
+
56
+ # update the sentence to be aware of it's current styleguide context
57
+ withins = []
58
+ styleguide_stack.reverse_each do |context|
59
+ sentence << 'in'
60
+ context = context.to_a
61
+ sentence.concat(context)
62
+ withins.concat(context)
63
+ end
64
+ unless withins.empty?
65
+ sentence << 'within'
66
+ sentence.concat(withins)
67
+ end
21
68
 
22
69
  id, modifiers = grammarize(sentence, styleguideIds)
23
70
 
@@ -30,6 +77,13 @@ module Archetype::SassExtensions::Styleguide
30
77
  # maybe in the case where we're looking for strict keys on the lookup?
31
78
  modifiers = modifiers.uniq
32
79
  token = memoizer.tokenize(theme[:name], extensions, id, modifiers, state)
80
+ if id
81
+ _styleguide_debug "the computed grammar is...", :grammar
82
+ _styleguide_debug " identifier: #{id}", :grammar
83
+ unless modifiers.empty?
84
+ _styleguide_debug " modifiers: #{modifiers.join(', ')}", :grammar
85
+ end
86
+ end
33
87
  return id, modifiers, token
34
88
  end
35
89
 
@@ -46,7 +100,7 @@ module Archetype::SassExtensions::Styleguide
46
100
  sentence = sentence.to_a
47
101
  id = nil
48
102
  modifiers = []
49
- if not sentence.empty?
103
+ unless sentence.empty?
50
104
  prefix = ''
51
105
  order = ''
52
106
  # these define various attributes for modifiers (e.g. `button with a shadow`)
@@ -54,16 +108,23 @@ module Archetype::SassExtensions::Styleguide
54
108
  # these are things that are useless to us, so we just leave them out
55
109
  ignore = %w(a an also the this that is was it)
56
110
  # these are our context switches (e.g. `headline in a button`)
57
- contexts = %w(in within)
111
+ local_contexts = %w(in)
112
+ # these are the contexts that match all surrounding items
113
+ global_contexts = %w(within)
114
+
58
115
  sentence.each do |item|
59
116
  item = item.value if not item.is_a?(String)
60
117
  # find the ID
61
118
  if id.nil? and ids.include?(item) and prefix.empty? and order.empty?
62
119
  id = item
63
- # if it's a `context`, we need to increase the depth and reset the prefix
64
- elsif contexts.include?(item)
120
+ # if it's a `local context`, we need to increase the depth and reset the prefix
121
+ elsif local_contexts.include?(item)
65
122
  order = "#{item}-#{order}"
66
123
  prefix = ''
124
+ # if it's a `global context`, we need to reset the order, but also update the prefix
125
+ elsif global_contexts.include?(item)
126
+ order = ''#"#{item}-"
127
+ prefix = "#{item}-"
67
128
  # if it's an `extra`, we update the prefix
68
129
  elsif extras.include?(item)
69
130
  prefix = "#{item}-"
@@ -6,6 +6,41 @@ module Archetype::SassExtensions::Styleguide
6
6
  Archetype::Functions::StyleguideMemoizer
7
7
  end
8
8
 
9
+ #
10
+ # ouputs a debug message for styleguide / component methods
11
+ #
12
+ # valid types...
13
+ # :get, :get_granular, :diff, :add, :extend, :remove, :freeze, :grammar, :drop, :inherit, :resolve, :extract
14
+ #
15
+ def _styleguide_debug(msg, type = :all)
16
+ debug = Compass.configuration.styleguide_debug
17
+ debug = :all if debug == true
18
+ debug = [debug] unless debug.is_a? Array
19
+ if debug.include?(type) || debug.include?(:all)
20
+ begin
21
+ if msg.is_a? String
22
+ helpers.debug("[archetype:styleguide] #{msg}")
23
+ else
24
+ puts ">" * 50
25
+ pp msg
26
+ puts "<" * 50
27
+ end
28
+ rescue
29
+ end
30
+ end
31
+ end
32
+
33
+ #
34
+ # helper for operations that need to happen within a mutex
35
+ #
36
+ def _styleguide_mutex_helper(id = nil, theme = nil)
37
+ (@@archetype_styleguide_mutex ||= Mutex.new).synchronize do
38
+ if block_given?
39
+ id.nil? ? yield : yield(helpers.to_str(id), get_theme(theme))
40
+ end
41
+ end
42
+ end
43
+
9
44
  #
10
45
  # normalize the styleguide definition into a hash representative of the definition
11
46
  #
@@ -24,7 +59,7 @@ module Archetype::SassExtensions::Styleguide
24
59
  end
25
60
 
26
61
  def self.reset!(filename = nil)
27
- @@archetype_styleguide_mutex.synchronize do
62
+ (@@archetype_styleguide_mutex ||= Mutex.new).synchronize do
28
63
  if filename.nil?
29
64
  @@styleguide_themes = {}
30
65
  else
@@ -22,7 +22,10 @@ module Archetype::SassExtensions::Styleguide
22
22
  if not drop.nil?
23
23
  drop.to_a.each do |key|
24
24
  key = helpers.to_str(key)
25
- obj.delete(key) if not SPECIAL.include?(key)
25
+ if not SPECIAL.include?(key)
26
+ _styleguide_debug "dropping styles for `#{key}`", :drop
27
+ obj.delete(key)
28
+ end
26
29
  end
27
30
  merger.delete(DROP)
28
31
  end
@@ -84,6 +87,7 @@ module Archetype::SassExtensions::Styleguide
84
87
  # - <tt>key</tt> {String} the key we care about
85
88
  #
86
89
  def special_drop_key(obj, tmp, key)
90
+ _styleguide_debug "dropping styles for `#{key}`", :drop
87
91
  if SPECIAL.include?(key)
88
92
  if not (obj[key].nil? or obj[key].empty?)
89
93
  tmp[key] = Archetype::Hash.new
@@ -108,6 +112,7 @@ module Archetype::SassExtensions::Styleguide
108
112
  #
109
113
  def resolve_dependents(id, value, theme = nil, context = nil, obj = nil)
110
114
  return value if value.nil?
115
+ debug = Compass.configuration.styleguide_debug
111
116
  # we have to create a clone here as the passed in value is volatile and we're performing destructive changes
112
117
  value = value.clone
113
118
  # check that we're dealing with a hash
@@ -126,7 +131,10 @@ module Archetype::SassExtensions::Styleguide
126
131
  if not inherit.empty?
127
132
  # create a temporary object and extract the nested styles
128
133
  tmp = Archetype::Hash.new
129
- inherit.each { |related| tmp = tmp.rmerge(extract_styles(id, related, true, theme, context)) }
134
+ inherit.each do |related|
135
+ _styleguide_debug "inheriting from `#{helpers.to_str(related)}`", :inherit
136
+ tmp = tmp.rmerge(extract_styles(id, related, true, theme, context))
137
+ end
130
138
  # remove the inheritance key and update the styles
131
139
  value.delete(INHERIT)
132
140
  inherit = extract_styles(id, inherit, true, theme, context)
@@ -136,6 +144,8 @@ module Archetype::SassExtensions::Styleguide
136
144
  end
137
145
  end
138
146
  # return whatever we got
147
+ _styleguide_debug "after resolving dependents...", :resolve
148
+ _styleguide_debug value, :resolve
139
149
  return value
140
150
  end
141
151
 
@@ -24,14 +24,15 @@ module Archetype::SassExtensions::Styleguide
24
24
  out = out.clone
25
25
  return Archetype::Hash.new if out == null
26
26
  # if it's not strict, find anything that matched
27
- if not strict
27
+ unless strict
28
28
  modifiers = modifiers.split
29
29
  context.each do |key, definition|
30
30
  modifier = grammarize(key.split(' '))[1].join(' ')
31
- if modifier != DEFAULT
31
+ unless modifier == DEFAULT
32
32
  match = true
33
33
  modifier = modifier.split
34
34
  if modifier[0] == REGEX
35
+ _styleguide_debug "finding regex matches", :extract
35
36
  # if it's a regex pattern, test if it matches
36
37
  match = modifiers.join(' ') =~ /#{modifier[1].gsub(/\A"|"\Z/, '')}/i
37
38
  else
@@ -40,6 +41,7 @@ module Archetype::SassExtensions::Styleguide
40
41
  end
41
42
  # if it matched, process it
42
43
  if match
44
+ _styleguide_debug "`#{key}` is a matching variant", :extract
43
45
  tmp = resolve_dependents(id, definition, theme[:name], nil, out)
44
46
  out, tmp = post_resolve_drops(out, tmp)
45
47
  out = out.rmerge(tmp) if not helpers.is_value(tmp, :nil)
@@ -112,13 +114,14 @@ module Archetype::SassExtensions::Styleguide
112
114
  extracted = extract_styles(id, modifiers, false, theme)
113
115
  # we can delete anything that had a value of `nil` as we won't be outputting those
114
116
  extracted.delete_if { |k,v| helpers.is_value(v, :nil) }
117
+ _styleguide_debug extracted, :get_granular
115
118
  # expose the result to the block
116
119
  extracted
117
120
  end
118
121
  styles = styles.rmerge(extracted)
119
122
  elsif not helpers.is_value(sentence, :nil)
120
123
  msg = modifiers.length > 0 ? "please specify one of: #{modifiers.sort.join(', ')}" : "there are no registered components"
121
- helpers.warn("[#{Archetype.name}:styleguide:missing_identifier] `#{helpers.to_str(sentence)}` does not contain an identifier. #{msg}")
124
+ helpers.warn("[#{Archetype.name}:styleguide:identifier] `#{helpers.to_str(sentence)}` does not contain an identifier. #{msg}")
122
125
  end
123
126
  end
124
127
 
@@ -21,7 +21,7 @@ module Archetype::SassExtensions::Styleguide
21
21
  theme_name = helpers.to_str(theme || environment.var('CONFIG_THEME') || Archetype.name)
22
22
  key = nil
23
23
  begin
24
- key = environment.options[:css_filename].hash
24
+ key = environment.options[:css_filename]
25
25
  end
26
26
  # if we're aggressively memoizing, store everything across the session
27
27
  if Compass.configuration.memoize == :aggressive or not key
@@ -34,6 +34,7 @@ module Archetype::SassExtensions::Styleguide
34
34
  theme[:name] ||= theme_name
35
35
  theme[:components] ||= {}
36
36
  theme[:extensions] ||= []
37
+ theme[:frozen] ||= Set.new
37
38
  return theme
38
39
  end
39
40
 
@@ -75,7 +75,7 @@ module Archetype::SassExtensions::UI::Glyphs
75
75
  def register_glyph_library(key, library)
76
76
  registry = archetype_glyphs_registry
77
77
  # if it's already in the registry, just return the current list
78
- if is_null(registry[key])
78
+ if helpers.is_null(registry[key])
79
79
  registry = registry.dup
80
80
  registry[key] = library
81
81
  registry = Sass::Script::Value::Map.new(registry)
@@ -14,7 +14,7 @@ module Archetype::SassExtensions::UI::Scopes
14
14
  # we need a dup as the Hash is frozen
15
15
  breakpoints = registered_breakpoints.dup
16
16
  force = force.nil? ? false : force.value
17
- not_registered = breakpoints[key].nil? || is_null(breakpoints[key]).value
17
+ not_registered = breakpoints[key].nil? || helpers.is_null(breakpoints[key])
18
18
  # if there's no key registered...
19
19
  if force || not_registered
20
20
  # just register the value
@@ -61,9 +61,9 @@ module Archetype::SassExtensions::UI::Scopes
61
61
  modifier_separator = environment.var('CONFIG_BEM_MODIFIER_SEPARATOR')
62
62
  modifier_separator = modifier_separator.nil? ? '--' : modifier_separator.value
63
63
 
64
- context = is_null(context).value ? '' : context.value
65
- element = is_null(element).value ? nil : element.value
66
- modifier = is_null(modifier).value ? nil : modifier.value
64
+ context = helpers.is_null(context) ? '' : context.value
65
+ element = helpers.is_null(element) ? nil : element.value
66
+ modifier = helpers.is_null(modifier) ? nil : modifier.value
67
67
 
68
68
  selector = context
69
69
 
@@ -13,7 +13,7 @@ module Archetype::SassExtensions::Util::Debug
13
13
  return bool(false) unless (environment.var('CONFIG_DEBUG_ENVS') || []).to_a.include?(archetype_env)
14
14
  # then check if the debug flag/override is truthy
15
15
  # if the param is non-null, then use it
16
- return iff unless is_null(iff).value
16
+ return iff unless helpers.is_null(iff)
17
17
  # otherwise, use `CONFIG_DEBUG`
18
18
  return environment.var('CONFIG_DEBUG') || bool(false)
19
19
  end
@@ -1,7 +1,7 @@
1
1
  module Archetype::SassExtensions::Util::Hacks
2
2
 
3
3
  #
4
- # parse a CSS content string and format it for injection into innerHTML
4
+ # parse a CSS content string and format it for injection into innerText
5
5
  #
6
6
  # *Parameters*:
7
7
  # - <tt>$content</tt> {String} the CSS content string
@@ -10,14 +10,10 @@ module Archetype::SassExtensions::Util::Hacks
10
10
  #
11
11
  def _ie_pseudo_content(content)
12
12
  content = helpers.to_str(content)
13
- # escape &
14
- content = content.gsub(/\&/, '&amp;')
15
- # convert char codes (and remove single trailing whitespace if present) (e.g. \2079 -> &#x2079;)
16
- content = content.gsub(/\\([\da-fA-F]{4})\s?/, '&#x\1;')
17
- # escape tags and cleanup quotes
18
- content = content.gsub(/\</, '&lt;').gsub(/\>/, '&gt;')
13
+ # convert char codes (e.g. `\2079` -> `\u2079`)
14
+ content.gsub!(/\\([\da-fA-F]{4})\s?/, ['\1'.hex].pack('U*'))
19
15
  # cleanup quotes
20
- content = content.gsub(/\A"|"\Z/, '').gsub(/\"/, '\\"')
16
+ content.gsub!(/\A"|"\Z/, '').gsub!(/\"/, '\\"')
21
17
  return identifier(content)
22
18
  end
23
19
 
@@ -24,8 +24,7 @@ module Archetype::SassExtensions::Util::Images
24
24
  # - {Boolean} is the sprite set
25
25
  #
26
26
  def _archetype_check_sprite(map)
27
- status = !(global_sprites_disabled? && (is_null(map) || !map.value))
28
- return bool(status)
27
+ return bool(_is_sprite_valid(map))
29
28
  end
30
29
  Sass::Script::Functions.declare :_archetype_check_sprite, [:map]
31
30
 
@@ -41,7 +40,7 @@ module Archetype::SassExtensions::Util::Images
41
40
  # - {Sprite} the sprite object or `null`
42
41
  #
43
42
  def _archetype_sprite(map, sprite, offset_x = number(0), offset_y = number(0))
44
- return null unless _archetype_check_sprite(map)
43
+ return null unless _is_sprite_valid(map)
45
44
  return sprite(map, sprite, offset_x, offset_y)
46
45
  end
47
46
  Sass::Script::Functions.declare :_archetype_sprite, [:map, :sprite, :offset_x, :offset_y]
@@ -58,7 +57,7 @@ module Archetype::SassExtensions::Util::Images
58
57
  # - {List} the sprite position or `null`
59
58
  #
60
59
  def _archetype_sprite_position(map, sprite, offset_x = number(0), offset_y = number(0))
61
- return null unless _archetype_check_sprite(map)
60
+ return null unless _is_sprite_valid(map)
62
61
  return sprite_position(map, sprite, offset_x, offset_y)
63
62
  end
64
63
  Sass::Script::Functions.declare :_archetype_sprite_position, [:map, :sprite, :offset_x, :offset_y]
@@ -72,7 +71,7 @@ module Archetype::SassExtensions::Util::Images
72
71
  # - {String} the sprite URL or `null`
73
72
  #
74
73
  def _archetype_sprite_url(map)
75
- return null unless _archetype_check_sprite(map)
74
+ return null unless _is_sprite_valid(map)
76
75
  return sprite_url(map)
77
76
  end
78
77
  Sass::Script::Functions.declare :_archetype_sprite_url, [:map]
@@ -87,7 +86,7 @@ module Archetype::SassExtensions::Util::Images
87
86
  # - {ImageFile} the image or `null`
88
87
  #
89
88
  def _archetype_sprite_file(map, sprite)
90
- return null unless _archetype_check_sprite(map)
89
+ return null unless _is_sprite_valid(map)
91
90
  return sprite_file(map, sprite)
92
91
  end
93
92
  Sass::Script::Functions.declare :_archetype_sprite_file, [:map, :sprite]
@@ -102,7 +101,7 @@ module Archetype::SassExtensions::Util::Images
102
101
  # - {Number} the width of the image or `null`
103
102
  #
104
103
  def _archetype_image_width(image)
105
- return null if is_null(image).value
104
+ return null if helpers.is_null(image)
106
105
  return image_width(image)
107
106
  end
108
107
  Sass::Script::Functions.declare :_archetype_image_width, [:image]
@@ -117,13 +116,17 @@ module Archetype::SassExtensions::Util::Images
117
116
  # - {Number} the height of the image or `null`
118
117
  #
119
118
  def _archetype_image_height(image)
120
- return null if is_null(image).value
119
+ return null if helpers.is_null(image)
121
120
  return image_height(image)
122
121
  end
123
122
  Sass::Script::Functions.declare :_archetype_image_height, [:image]
124
123
 
125
124
  private
126
125
 
126
+ def _is_sprite_valid(map)
127
+ return !global_sprites_disabled? && !(helpers.is_null(map) || !map.value)
128
+ end
129
+
127
130
  def global_sprites_disabled?
128
131
  sprites_disabled = environment.var('CONFIG_DISABLE_STYLEGUIDE_SPRITES')
129
132
  return sprites_disabled.respond_to?(:value) ? sprites_disabled.value : false
@@ -124,7 +124,7 @@ module Archetype::SassExtensions::Util::Misc
124
124
  def do_once(name)
125
125
  registry = do_once_registry
126
126
  # if it's already in the registry, just return `false`
127
- return bool(false) if do_once_registry.include?(name)
127
+ return bool(false) if registry.include?(name)
128
128
  # update the registry with the identifier
129
129
  registry = list(registry.dup.push(name), :comma)
130
130
  environment.global_env.set_var('REGISTRY_DO_ONCE', registry)
@@ -202,6 +202,35 @@ module Archetype::SassExtensions::Util::Misc
202
202
  return best_match
203
203
  end
204
204
 
205
+ def _archetype_within_mixin(contexts)
206
+ stack = archetype_mixin_stack
207
+ contexts = contexts.is_a?(Sass::Script::Value::List) ? contexts.to_a : [contexts]
208
+ contexts.each do |context|
209
+ return bool(true) if stack.include?(context.to_s.gsub(/_/, '-').downcase )
210
+ end
211
+ return bool(false)
212
+ end
213
+
214
+ def _archetype_mixin_called_recursively()
215
+ stack = archetype_mixin_stack
216
+ current = stack.shift
217
+ return bool(stack.include?(current))
218
+ end
219
+
220
+ #
221
+ # normalizes a property
222
+ #
223
+ # *Parameters*:
224
+ # - <tt>$property</tt> {String} the property
225
+ # *Returns*:
226
+ # - {String} the normalized property
227
+ #
228
+ def _archetype_normalize_property(property)
229
+ return null if helpers.is_null(property)
230
+ property = helpers.to_str(property)
231
+ return identifier(property.gsub(/\:.*/, ''))
232
+ end
233
+
205
234
  private
206
235
 
207
236
  @@archetype_ui_mutex = Mutex.new
@@ -213,6 +242,10 @@ private
213
242
  end
214
243
  end
215
244
 
245
+ def archetype_mixin_stack
246
+ @environment.stack.frames.select {|f| f.is_mixin?}.reverse!.map! {|f| f.name.gsub(/_/, '-').downcase }
247
+ end
248
+
216
249
  def do_once_registry
217
250
  (environment.var('REGISTRY_DO_ONCE') || []).to_a
218
251
  end