archetype 0.0.1.pre.3.f9dde24 → 0.0.1.pre.3.90263a7

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/bin/archetype +3 -0
  3. data/lib/archetype/actions/help.rb +16 -0
  4. data/lib/archetype/actions/theme.rb +73 -0
  5. data/lib/archetype/executor.rb +27 -0
  6. data/lib/archetype/functions/helpers.rb +49 -9
  7. data/lib/archetype/functions/styleguide_memoizer.rb +9 -1
  8. data/lib/archetype/sass_extensions.rb +1 -0
  9. data/lib/archetype/sass_extensions/functions/styleguide.rb +104 -27
  10. data/lib/archetype/sass_extensions/monkey_patches.rb +3 -0
  11. data/lib/archetype/sass_extensions/monkey_patches/handle_include_loop.rb +41 -0
  12. data/stylesheets/archetype/_base.scss +3 -0
  13. data/stylesheets/archetype/_config.scss +5 -1
  14. data/stylesheets/archetype/_hacks.scss +24 -4
  15. data/stylesheets/archetype/_ui.scss +23 -2
  16. data/stylesheets/archetype/base/_h5bp.scss +12 -12
  17. data/stylesheets/archetype/base/_normalize.scss +178 -139
  18. data/stylesheets/archetype/styleguide/_helpers.scss +1 -4
  19. data/stylesheets/archetype/styleguide/components/_alerts.scss +1 -1
  20. data/stylesheets/archetype/styleguide/components/_buttons.scss +6 -6
  21. data/stylesheets/archetype/styleguide/components/_closes.scss +2 -2
  22. data/stylesheets/archetype/util/_styles.scss +18 -3
  23. data/stylesheets/archetype/util/_targeting.scss +2 -0
  24. data/templates/_theme/_components.scss +3 -0
  25. data/templates/_theme/_config.scss +1 -0
  26. data/templates/_theme/_core.scss +13 -0
  27. data/templates/_theme/_helpers.scss +1 -0
  28. data/templates/_theme/_primitives.scss +3 -0
  29. data/templates/_theme/components/README +1 -0
  30. data/templates/_theme/primitives/README +1 -0
  31. data/test/fixtures/stylesheets/archetype/expected/styleguide/alerts.css +675 -0
  32. data/test/fixtures/stylesheets/archetype/expected/styleguide/buttons.css +18 -18
  33. data/test/fixtures/stylesheets/archetype/expected/styleguide/drop.css +63 -0
  34. data/test/fixtures/stylesheets/archetype/expected/styleguide/invalid_structures.css +21 -0
  35. data/test/fixtures/stylesheets/archetype/expected/styleguide/multi_value.css +13 -0
  36. data/test/fixtures/stylesheets/archetype/expected/ui/glyph_icon.css +52 -9
  37. data/test/fixtures/stylesheets/archetype/expected/utilities/targeting/target-browser.css +5 -0
  38. data/test/fixtures/stylesheets/archetype/source/styleguide/alerts.scss +21 -0
  39. data/test/fixtures/stylesheets/archetype/source/styleguide/buttons.scss +1 -1
  40. data/test/fixtures/stylesheets/archetype/source/styleguide/drop.scss +101 -0
  41. data/test/fixtures/stylesheets/archetype/source/styleguide/fallback_styles.scss +1 -1
  42. data/test/fixtures/stylesheets/archetype/source/styleguide/invalid_structures.scss +85 -0
  43. data/test/fixtures/stylesheets/archetype/source/styleguide/multi_value.scss +18 -0
  44. data/test/fixtures/stylesheets/archetype/source/styleguide/nested_styleguides.scss +1 -1
  45. data/test/fixtures/stylesheets/archetype/source/styleguide/selective_state.scss +1 -1
  46. data/test/fixtures/stylesheets/archetype/source/ui/glyph_icon.scss +10 -0
  47. data/test/fixtures/stylesheets/archetype/source/utilities/targeting/target-browser.scss +8 -1
  48. metadata +33 -5
  49. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders-s7889ccc8c1.png +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9d8111354af528e1158bffdbf5a605d91777d741
4
- data.tar.gz: aeb843b2e32d7c191c5e0e137baa48b835021f3f
3
+ metadata.gz: 79510cfaba6afef89a552a3ac086173c80c73822
4
+ data.tar.gz: 2214d9ff17d64a4fab9829e870ac8849e952cec4
5
5
  SHA512:
6
- metadata.gz: d9e9e587c6300790c9b16e4ce8547312ffa74b224dc981512a99af210b5433413d695786e08def6ad2758e558ec12087be1d146bfb9166d8f616b5300139737d
7
- data.tar.gz: e13543614e78725f830aa69078645e419d84ab42b5d01063a6847830c7458952147056a953fed0a82e618d269799cfc10201f3c31776658171962cf112b799c7
6
+ metadata.gz: 90fd7abc4d5707b492d987a3e0870b911f27d08e1baec5a16bee065f101927ce44a443727cb0b3640a2a0fa509cac2c9f4ce29a34709645f6637f12214bee1f3
7
+ data.tar.gz: 95fa9484e95e38ad062889e68bb11aa2d7d21a4edbb2c1e9db8be53b729ba1d795d9a1ca67e8586526493486770d51a976a593937218166c4e38637e00a271b6
data/bin/archetype ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'lib/archetype/executor')
@@ -0,0 +1,16 @@
1
+ description = "Get help on an Archetype action"
2
+ if @description.nil?
3
+ # do stuff...
4
+ @help = true
5
+
6
+ if not ARGV[1].nil? and ARGV[1] != 'help'
7
+ action = File.join(@actions_path, ARGV[1])
8
+ begin
9
+ load "#{action}.rb"
10
+ rescue
11
+ puts "unknown action: #{ARGV[1]}"
12
+ end
13
+ end
14
+ else
15
+ @description = description
16
+ end
@@ -0,0 +1,73 @@
1
+ require 'fileutils'
2
+ description = "Generate a new Archetype theme"
3
+
4
+ if @description.nil?
5
+ options = {
6
+ :extends => 'archetype'
7
+ }
8
+ OptionParser.new do |opts|
9
+ opts.banner = description
10
+ opts.define_head "Usage: archetype theme [path] [options]"
11
+ opts.separator ""
12
+ opts.separator "Example usage:"
13
+ opts.separator " archetype theme /path/to/scss/ --name=myCustomTheme"
14
+ opts.separator " archetype theme --name=themes/myExtendedTheme --extends=themes/myBaseTheme"
15
+
16
+ opts.on('-n', '--name THEME', 'theme name') do |v|
17
+ options[:theme] = v
18
+ end
19
+
20
+ opts.on('-x', '--extends THEME', 'theme name to extend') do |v|
21
+ options[:extends] = v
22
+ end
23
+
24
+ opts.on('-h', '--help', 'shows this help message') do
25
+ puts opts
26
+ exit
27
+ end
28
+
29
+ if not @help.nil?
30
+ puts opts
31
+ exit
32
+ end
33
+ end.parse!
34
+
35
+ if not options[:theme].nil?
36
+ base = ARGV[1] || '.'
37
+ tmp = '/tmp/theme_' + rand(36**8).to_s(36)
38
+ theme_template = File.join(File.dirname(__FILE__), '../../../templates/_theme/')
39
+ theme_path = File.join(base, options[:theme])
40
+ extends = "#{options[:extends]}"
41
+ if options[:extends] != 'archetype'
42
+ extends = "#{extends}/core"
43
+ end
44
+ theme_name = File.basename(options[:theme])
45
+ # copy template files to tmp dir
46
+ FileUtils.mkdir_p(tmp)
47
+ FileUtils.cp_r(Dir["#{theme_template}/**"], tmp)
48
+
49
+ puts "Creating theme '#{theme_name}' in #{File.expand_path(theme_path)}..."
50
+ puts "extending from #{options[:extends]}" if options[:extends] != 'archetype'
51
+
52
+ # update all placeholders in template files
53
+ Dir.glob("#{tmp}/**/*.scss") do |filename|
54
+ out = File.read(filename).gsub(/__THEME_NAME__/, theme_name).gsub(/__THEME_EXTENDS__/, extends)
55
+ File.open(filename, "w") { |file| file.puts out }
56
+ end
57
+
58
+ # now move all the theme files to their destination
59
+ FileUtils.mkdir_p(theme_path)
60
+ FileUtils.cp_r(Dir["#{tmp}/**"], theme_path)
61
+
62
+ # create convenience file _<theme>.scss ...
63
+ File.open(File.join(File.dirname(theme_path), "_#{theme_name}.scss"), "w") { |file| file.puts "// #{theme_name} theme\n@import \"#{theme_name}/core\";\n" }
64
+
65
+ # remove tmp dir
66
+ FileUtils.rm_rf(tmp)
67
+ puts "Congratulations! Your new theme has been created!"
68
+ puts "Use @import \"#{options[:theme]}\" in your scss files."
69
+ exit
70
+ end
71
+ else
72
+ @description = description
73
+ end
@@ -0,0 +1,27 @@
1
+ require 'optparse'
2
+
3
+ @actions_path = File.join(File.dirname(__FILE__), 'actions')
4
+
5
+ if not ARGV[0].nil? and not ARGV[0].empty?
6
+ action_name = ARGV[0]
7
+ action = File.join(@actions_path, action_name)
8
+ begin
9
+ require action
10
+ rescue
11
+ puts "unknown action: #{action_name}"
12
+ end
13
+ end
14
+
15
+ # if we got here, there was either no action, or the action was invalid
16
+ OptionParser.new do |opts|
17
+ opts.banner = "Archetype command line actions\n\n"
18
+ opts.define_head "Usage: archetype <action> [options]"
19
+ opts.separator ""
20
+ opts.separator "Available Actions:"
21
+ Dir.glob("#{@actions_path}/*.rb") do |action|
22
+ @description = true
23
+ load action
24
+ opts.separator " * #{File.basename(action, '.rb')}\t- #{@description}"
25
+ end
26
+ puts opts
27
+ end.parse!
@@ -55,30 +55,66 @@ private
55
55
  #
56
56
  def self.list_to_hash(list, depth = 0, nest = [], additives = [])
57
57
  list = list.to_a
58
+ previous = nil
58
59
  hsh = Archetype::Hash.new
59
60
  list.each do |item|
60
61
  item = item.to_a
62
+
63
+ # if a 3rd item exists, we probably forgot a comma or parens somewhere
64
+ if previous.nil? and not item[2].nil?
65
+ msg = "you're likely missing a comma or parens in your data structure"
66
+ begin
67
+ logger.record(:warning, "#{msg}: #{item}")
68
+ rescue
69
+ logger.record(:warning, msg)
70
+ end
71
+ end
72
+
61
73
  # convert the key to a string and strip off quotes
62
74
  key = to_str(item[0], ' ' , :quotes)
75
+ # capture the value
63
76
  value = item[1]
77
+
64
78
  if key != 'nil'
79
+ if is_value(value, :blank)
80
+ if previous.nil?
81
+ previous = key
82
+ next
83
+ else
84
+ value = item[0]
85
+ key = previous
86
+ previous = nil
87
+ end
88
+ elsif not previous.nil?
89
+ # if we got here, something is wrong with the structure
90
+ list.shift if to_str(list[0]) == previous # remove the first item if it's the previous key, which is now the parent key
91
+ list = list[0].to_a # now the remaining items were munged, so split them out
92
+ hsh = Archetype::Hash.new
93
+ hsh[previous] = list_to_hash(list, depth - 1, nest, additives)
94
+ return hsh
95
+ end
96
+ end
97
+
98
+ # update the hash if we have a valid key and hash
99
+ if key != 'nil' and not is_value(value, :blank)
65
100
  # check if if it's a nesting hash
66
101
  nested = nest.include?(key)
67
102
  # if it's nested or we haven't reached out depth, recurse
68
103
  if nested or depth > 0
69
104
  value = list_to_hash(value, nested ? depth + 1 : depth - 1, nest, additives)
70
105
  end
71
- # update the hash key
72
- if not is_value(value, :blank)
73
- if additives.include?(key)
74
- hsh[key] ||= []
75
- hsh[key].push(value)
76
- else
77
- hsh[key] = value
78
- end
106
+
107
+ if additives.include?(key)
108
+ hsh[key] ||= []
109
+ hsh[key].push(value)
110
+ else
111
+ hsh[key] = value
79
112
  end
80
113
  end
81
114
  end
115
+
116
+ logger.record(:warning, "one of your data structures is ambiguous, please double check near `#{previous}`") if not previous.nil?
117
+
82
118
  return hsh
83
119
  end
84
120
 
@@ -92,7 +128,9 @@ private
92
128
  # - {String} the converted String
93
129
  #
94
130
  def self.to_str(value, separator = ' ', strip = nil)
95
- value = value.is_a?(String) ? value : ((value.to_a).each{ |i| i.is_a?(String) ? i : i.value }).join(separator || '')
131
+ if not value.is_a?(String)
132
+ value = ((value.to_a).each{ |i| i.nil? ? 'nil' : (i.is_a?(String) ? i : i.value) }).join(separator || '')
133
+ end
96
134
  strip = /\A"|"\Z/ if strip == :quotes
97
135
  return strip.nil? ? value : value.gsub(strip, '')
98
136
  end
@@ -112,11 +150,13 @@ private
112
150
  when :blank
113
151
  is_it = false
114
152
  value = value.value if value.is_a?(Sass::Script::String)
153
+ is_it = value.nil?
115
154
  is_it = value.empty? if value.is_a?(String)
116
155
  is_it = value.to_a.empty? if value.is_a?(Sass::Script::List) or value.is_a?(Array)
117
156
  when :nil
118
157
  is_it = false
119
158
  value = value.value if value.is_a?(Sass::Script::String)
159
+ is_it = value.nil?
120
160
  is_it = value == 'nil' if value.is_a?(String)
121
161
  is_it = to_str(value) == 'nil' if value.is_a?(Sass::Script::List) or value.is_a?(Array)
122
162
  end
@@ -50,7 +50,7 @@ private
50
50
  end
51
51
 
52
52
  #
53
- # invalidate the entire memoizer for the theme
53
+ # invalidate the memoizer for the theme
54
54
  #
55
55
  # *Parameters*:
56
56
  # - <tt>theme</tt> {String} the theme name
@@ -58,4 +58,12 @@ private
58
58
  def self.clear(theme)
59
59
  @components[theme] = {}
60
60
  end
61
+
62
+
63
+ #
64
+ # resets the entire memoizer
65
+ #
66
+ def self.reset!
67
+ @components = {}
68
+ end
61
69
  end
@@ -4,3 +4,4 @@ module Archetype::SassExtensions
4
4
  end
5
5
 
6
6
  require 'archetype/sass_extensions/functions'
7
+ require 'archetype/sass_extensions/monkey_patches'
@@ -15,10 +15,13 @@ module Archetype::SassExtensions::Styleguide
15
15
  DEFAULT = 'default'
16
16
  REGEX = 'regex'
17
17
  SPECIAL = %w(states selectors)
18
+ DROPALL = %w(all true)
18
19
  # these are unique CSS keys that can be exploited to provide fallback functionality by providing a second value
19
20
  # e.g color: red; color: rgba(255,0,0, 0.8);
20
21
  FALLBACKS = %w(background background-image background-color border border-bottom border-bottom-color border-color border-left border-left-color border-right border-right-color border-top border-top-color clip color layer-background-color outline outline-color white-space extend)
21
- ADDITIVES = FALLBACKS + [DROP, INHERIT, STYLEGUIDE]
22
+ # these are mixins that make sense to run multiple times within a block
23
+ MULTIMIXINS = %w(target-browser)
24
+ ADDITIVES = FALLBACKS + [DROP, INHERIT, STYLEGUIDE] + MULTIMIXINS
22
25
  @@archetype_styleguide_mutex = Mutex.new
23
26
  # :startdoc:
24
27
 
@@ -246,7 +249,11 @@ private
246
249
  modifier.each { |i| match = false if not modifiers.include?(i) }
247
250
  end
248
251
  # if it matched, process it
249
- out = out.rmerge(resolve_dependents(id, definition[1], theme[:name], nil, out.keys)) if match
252
+ if match
253
+ tmp = resolve_dependents(id, definition[1], theme[:name], nil, out)
254
+ out, tmp = post_resolve_drops(out, tmp)
255
+ out = out.rmerge(tmp)
256
+ end
250
257
  end
251
258
  end
252
259
  end
@@ -254,15 +261,19 @@ private
254
261
  # this lets us define special states and elements
255
262
  SPECIAL.each do |special_key|
256
263
  if out.is_a? Hash
257
- special = out[special_key]
258
- tmp = Archetype::Hash.new
259
- (special || Archetype::Hash.new).each { |key, value| tmp[key] = extract_styles(key, key, true, theme[:name], special) }
260
- out[special_key] = tmp if not tmp.empty?
264
+ special = out[special_key] || Archetype::Hash.new
265
+ if special == 'nil'
266
+ out[special_key] = Archetype::Hash.new
267
+ else
268
+ tmp = Archetype::Hash.new
269
+ special.each { |key, value| tmp[key] = extract_styles(key, key, true, theme[:name], special) }
270
+ out[special_key] = tmp if not tmp.empty?
271
+ end
261
272
  end
262
273
  end
263
274
  # check for nested styleguides
264
275
  styleguide = out[STYLEGUIDE]
265
- if styleguide and not styleguide.empty?
276
+ if not (styleguide.nil? or styleguide.empty?)
266
277
  styles = get_styles(styleguide, theme[:name])
267
278
  out.delete(STYLEGUIDE)
268
279
  out = styles.rmerge(out)
@@ -270,6 +281,87 @@ private
270
281
  return out
271
282
  end
272
283
 
284
+ #
285
+ # given two objects, resolve the chain of dropped styles
286
+ # this runs after having already resolved the dropped styles and merged
287
+ #
288
+ # *Parameters*:
289
+ # - <tt>obj</tt> {Hash} the source object
290
+ # - <tt>merger</tt> {Hash} the object to be merged in
291
+ # *Returns*:
292
+ # - {Array.<Hash>} the resulting `obj` and `merger` objects
293
+ #
294
+ def post_resolve_drops(obj, merger)
295
+ return [obj, merger] if obj.nil? or merger.nil?
296
+ drop = merger[DROP]
297
+ keys = obj.keys
298
+ if not drop.nil?
299
+ drop.to_a.each do |key|
300
+ key = helpers.to_str(key)
301
+ obj.delete(key) if not SPECIAL.include?(key)
302
+ end
303
+ merger.delete(DROP)
304
+ else
305
+ end
306
+ SPECIAL.each do |special|
307
+ if obj[special].is_a?(Hash) and merger[special].is_a?(Hash)
308
+ obj[special], merger[special] = post_resolve_drops(obj[special], merger[special])
309
+ end
310
+ end
311
+ return [obj, merger]
312
+ end
313
+
314
+ #
315
+ # given two objects, resolve the chain of dropped styles
316
+ #
317
+ # *Parameters*:
318
+ # - <tt>value</tt> {Hash} the source object
319
+ # - <tt>obj</tt> {Hash} the object to be merged in
320
+ # - <tt>is_special</tt> {Boolean} whether this is from a SPECIAL branch of a Hash
321
+ # *Returns*:
322
+ # - {Array.<Hash>} the resulting value
323
+ #
324
+ def resolve_drops(value, obj, is_special = false)
325
+ return value if not (value.is_a?(Hash) and obj.is_a?(Hash))
326
+ keys = obj.keys
327
+ drop = value[DROP]
328
+ if not drop.nil?
329
+ tmp = Archetype::Hash.new
330
+ if DROPALL.include?(helpers.to_str(drop))
331
+ if not keys.nil?
332
+ keys.each do |key|
333
+ if SPECIAL.include?(key)
334
+ if not (obj[key].nil? or obj[key].empty?)
335
+ tmp[key] = Archetype::Hash.new
336
+ tmp[key][DROP] = obj[key].keys
337
+ end
338
+ else
339
+ tmp[key] = 'nil'
340
+ end
341
+ end
342
+ end
343
+ else
344
+ drop.to_a.each do |key|
345
+ key = helpers.to_str(key)
346
+ if SPECIAL.include?(key)
347
+ if not (obj[key].nil? or obj[key].empty?)
348
+ tmp[key] = Archetype::Hash.new
349
+ tmp[key][DROP] = obj[key].keys
350
+ end
351
+ else
352
+ tmp[key] = 'nil'
353
+ end
354
+ end
355
+ end
356
+ value.delete(DROP) if not is_special
357
+ value = tmp.rmerge(value)
358
+ end
359
+ value.each do |key|
360
+ value[key] = resolve_drops(value[key], obj[key], key, SPECIAL.include?(key)) if not value[key].nil?
361
+ end
362
+ return value
363
+ end
364
+
273
365
  #
274
366
  # resolve any dependent references from the component
275
367
  #
@@ -282,31 +374,17 @@ private
282
374
  # *Returns*:
283
375
  # - {Hash} a hash of the resolved styles
284
376
  #
285
- def resolve_dependents(id, value, theme = nil, context = nil, keys = nil)
377
+ def resolve_dependents(id, value, theme = nil, context = nil, obj = nil)
286
378
  # we have to create a clone here as the passed in value is volatile and we're performing destructive changes
287
379
  value = value.clone
288
380
  # check that we're dealing with a hash
289
381
  if value.is_a?(Hash)
290
382
  # check for dropped styles
291
- drop = value[DROP]
292
- if not drop.nil?
293
- tmp = Archetype::Hash.new
294
- if %w(all true).include?(helpers.to_str(drop)) and not keys.nil? and not keys.empty?
295
- keys.each do |key|
296
- tmp[key] = 'nil'
297
- end
298
- else
299
- drop = drop.to_a
300
- drop.each do |key|
301
- tmp[helpers.to_str(key)] = 'nil'
302
- end
303
- end
304
- value.delete(DROP)
305
- value = tmp.rmerge(value)
306
- end
383
+ value = resolve_drops(value, obj)
384
+
307
385
  # check for inheritance
308
386
  inherit = value[INHERIT]
309
- if inherit and not inherit.empty?
387
+ if not (inherit.nil? or inherit.empty?)
310
388
  # create a temporary object and extract the nested styles
311
389
  tmp = Archetype::Hash.new
312
390
  inherit.each { |related| tmp = tmp.rmerge(extract_styles(id, related, true, theme, context)) }
@@ -349,9 +427,8 @@ private
349
427
  #
350
428
  def get_styles(description, theme = nil, state = 'false')
351
429
  state = helpers.to_str(state)
352
- description = description.to_a
353
430
  styles = Archetype::Hash.new
354
- description.each do |sentence|
431
+ description.to_a.each do |sentence|
355
432
  # get the grammar from the sentence
356
433
  id, modifiers, token = grammar(sentence, theme, state)
357
434
  if id