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

Sign up to get free protection for your applications and to get access to all the features.
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