require 'thread'
module Archetype::SassExtensions::Util::Misc
#
# simple test for `null` or `nil` (deprecated) value. this is here for back-compat support with old `nil` syntax
#
# *Parameters*:
# - $value {*} the value to test
# *Returns*:
# - {Boolean} whether or not the value is null
#
def is_null(value)
return bool(helpers.is_null(value))
end
#
# converts individual arguments into an archetype meta object that can be stored on a key in a map
#
# *Parameters*:
# - args... {*} the values to put into the meta object
# *Returns*:
# - {Map} the meta object
#
def multiple_values(*args)
return helpers.array_to_meta(args)
end
#
# decorates a map so that the actual value can be resolved at runtime with the current locale
#
# *Parameters*:
# - $map {*} the map to decorate
# *Returns*:
# - {Map} the decorated meta object
#
def runtime_locale_value(map)
return helpers.meta_decorate(map, :runtime_locales)
end
#
# given a map with meta data, extract the message and substitute any key-value pairs (@see str-substitute)
#
# *Parameters*:
# - $map {Map} the map to observe
# - $subsitutes {Map} the map of substitutes
# *Returns*:
# - {String} the meta message
#
def meta_message(map, subsitutes = nil)
message = null
meta = map_get_meta(map)
message = str_substitute(map_get(meta, identifier(helpers::META[:message])), subsitutes) if not meta.value.nil?
return message
end
#
# check to see if a map key has multiple values
#
# *Parameters*:
# - $map {Map} the map to observe
# *Returns*:
# - {Boolean} whether or not the map key represents multiple values
#
def has_multiple_values(map)
meta = map_get_meta(map)
return map_has_key(meta, identifier(helpers::META[:has_multiples])) if not meta.value.nil?
return bool(false)
end
#
# check to see if a value is decorated with runtime locale values
#
# *Parameters*:
# - $value {*} the value to observe
# *Returns*:
# - {Boolean} whether or not the map is decorated with runtime locale values
#
def has_runtime_locale_value(value)
meta = map_get_meta(value)
return map_has_key(meta, identifier(helpers::META[:decorators][:runtime_locales])) if not meta.value.nil?
return bool(false)
end
#
# retrieve the archetype meta data from a map
#
# *Parameters*:
# - $map {Map} the map to observe
# *Returns*:
# - {Map} the data contained within the meta key
#
def map_get_meta(map)
if map.is_a?(Sass::Script::Value::Map) and map_has_key(map, identifier(helpers::META[:meta])).value
return map_get(map, identifier(helpers::META[:meta]))
end
return null
end
#
# given a map of styles, get the derived style of a given property
#
# *Parameters*:
# - $styles {Map} the map of styles
# - $properties {String|List} the properties to extract the derived styles for
# - $format {String} the format to return the results in [auto|map|list]
# - $strict {Boolean} if true, will only return an exact match, and not try to extrapolate the value
# *Returns*:
# - {List|Map|*} either a list/map of the values or the individual value itself
#
def derived_style(styles, properties = [], format = 'auto', strict = false)
strict = strict.value if strict.respond_to?(:value)
return Archetype::Functions::CSS.get_derived_styles(helpers.data_to_hash(styles), properties, helpers.to_str(format).to_sym, strict)
end
#
# helper function to prevent routines from executing multiple times
#
# *Parameters*:
# - $name {String} identifier to check/register
# *Returns*:
# - {Boolean} `true` if the first time invoked, `false` otherwise
#
def do_once(name)
registry = do_once_registry
# if it's already in the registry, just return `false`
return bool(false) if registry.include?(name)
# update the registry with the identifier
registry = list(registry.dup.push(name), :comma)
environment.global_env.set_var('REGISTRY_DO_ONCE', registry)
# return true
return bool(true)
end
#
# generate a tag name with a prefix
#
# *Parameters*:
# - $tag {String} the tag to prefix
# - $prefix {String} the prefix to prepend to the tag
# *Returns*:
# - {String} the prefix joined with the tag
#
def prefixed_tag(tag, prefix = environment.var('CONFIG_GENERATED_TAG_PREFIX'))
tag = tag.value
tag = "-#{tag}" unless tag.empty?
prefix = prefix.nil? ? 'x-archetype' : prefix.value
return identifier("#{prefix}#{tag}")
end
Sass::Script::Functions.declare :prefixed_tag, [:tag]
Sass::Script::Functions.declare :prefixed_tag, [:tag, :prefix]
#
# generate a unique token
#
# *Parameters*:
# - $prefix {String} a string to prefix the UID with, `class` and `id` will generate a unique selector
# *Returns*:
# - {String} the unique string
#
def unique(prefix = '')
prefix = helpers.to_str(prefix, ' ', :quotes)
prefix = '.' if prefix == 'class'
prefix = '#' if prefix == 'id'
suffix = (defined?(ArchetypeTestHelpers) || defined?(Test::Unit)) ? "RANDOM_UID" : "#{Time.now.to_i}-#{rand(36**8).to_s(36)}-#{uid}"
return identifier("#{prefix}archetype-uid-#{suffix}")
end
#
# tokenize a given value
#
# *Parameters*:
# - $item {*} the item to generate a unique hash from
# *Returns*:
# - {String} a token of the string
#
def tokenize(item)
prefix = helpers.to_str(environment.var('CONFIG_GENERATED_TAG_PREFIX') || Archetype.name) + '-'
token = prefix + item.hash.to_s
return identifier(token)
end
Sass::Script::Functions.declare :tokenize, [:item]
#
# extracts the value associated with the current locale from the given decorated object
#
# *Parameters*:
# - $item {*} the item check against
# *Returns*:
# - {*} the value given the current locale
#
def get_runtime_locale_value(item)
item = helpers.hash_to_map(item) if item.is_a?(Hash)
return item unless has_runtime_locale_value(item).value
item = map_get(item, identifier('original')).to_h
best_match = null
item.each do |lang, value|
if lang.value == 'default' or locale(lang).value
best_match = value
end
end
return best_match
end
def _archetype_within_mixin(contexts)
stack = archetype_mixin_stack
contexts = contexts.is_a?(Sass::Script::Value::List) ? contexts.to_a : [contexts]
contexts.each do |context|
return bool(true) if stack.include?(context.to_s.gsub(/_/, '-').downcase )
end
return bool(false)
end
def _archetype_mixin_called_recursively()
stack = archetype_mixin_stack
current = stack.shift
return bool(stack.include?(current))
end
#
# normalizes a property
#
# *Parameters*:
# - $property {String} the property
# *Returns*:
# - {String} the normalized property
#
def _archetype_normalize_property(property)
return null if helpers.is_null(property)
property = helpers.to_str(property)
return identifier(property.gsub(/\:.*/, ''))
end
private
@@archetype_ui_mutex = Mutex.new
def uid
@@archetype_ui_mutex.synchronize do
@@uid ||= 0
@@uid += 1
end
end
def archetype_mixin_stack
@environment.stack.frames.select {|f| f.is_mixin?}.reverse!.map! {|f| f.name.gsub(/_/, '-').downcase }
end
def do_once_registry
(environment.var('REGISTRY_DO_ONCE') || []).to_a
end
end