archetype 1.0.0.alpha.2 → 1.0.0.alpha.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.
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