archetype 0.0.1.pre.1 → 0.0.1.pre.3.00dfd9a

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 (185) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +88 -0
  3. data/LICENSE +16 -0
  4. data/README.md +87 -1
  5. data/VERSION.yml +6 -0
  6. data/lib/README.rdoc +4 -0
  7. data/lib/archetype.rb +45 -0
  8. data/lib/archetype/functions.rb +9 -0
  9. data/lib/archetype/functions/hash.rb +149 -0
  10. data/lib/archetype/functions/helpers.rb +125 -0
  11. data/lib/archetype/functions/styleguide_memoizer.rb +61 -0
  12. data/lib/archetype/sass_extensions.rb +6 -0
  13. data/lib/archetype/sass_extensions/functions.rb +14 -0
  14. data/lib/archetype/sass_extensions/functions/environment.rb +14 -0
  15. data/lib/archetype/sass_extensions/functions/lists.rb +284 -0
  16. data/lib/archetype/sass_extensions/functions/locale.rb +77 -0
  17. data/lib/archetype/sass_extensions/functions/numbers.rb +19 -0
  18. data/lib/archetype/sass_extensions/functions/styleguide.rb +406 -0
  19. data/lib/archetype/sass_extensions/functions/ui.rb +59 -0
  20. data/lib/archetype/sass_extensions/functions/version.rb +95 -0
  21. data/lib/archetype/version.rb +75 -0
  22. data/stylesheets/_archetype.scss +2 -0
  23. data/stylesheets/archetype/_base.scss +46 -0
  24. data/stylesheets/archetype/_config.scss +366 -0
  25. data/stylesheets/archetype/_grid.scss +3 -0
  26. data/stylesheets/archetype/_hacks.scss +72 -0
  27. data/stylesheets/archetype/_init.scss +23 -0
  28. data/stylesheets/archetype/_styleguide.scss +6 -0
  29. data/stylesheets/archetype/_ui.scss +326 -0
  30. data/stylesheets/archetype/_util.scss +12 -0
  31. data/stylesheets/archetype/base/_h5bp.scss +307 -0
  32. data/stylesheets/archetype/base/_hybrid.scss +25 -0
  33. data/stylesheets/archetype/base/_normalize.scss +595 -0
  34. data/stylesheets/archetype/base/_reset.scss +72 -0
  35. data/stylesheets/archetype/grid/_config.scss +14 -0
  36. data/stylesheets/archetype/grid/_grid.scss +391 -0
  37. data/stylesheets/archetype/styleguide/_components.scss +25 -0
  38. data/stylesheets/archetype/styleguide/_helpers.scss +215 -0
  39. data/stylesheets/archetype/styleguide/_primitives.scss +10 -0
  40. data/stylesheets/archetype/styleguide/_styleguide.scss +41 -0
  41. data/stylesheets/archetype/styleguide/components/_alerts.scss +59 -0
  42. data/stylesheets/archetype/styleguide/components/_annotations.scss +27 -0
  43. data/stylesheets/archetype/styleguide/components/_bristol.scss +15 -0
  44. data/stylesheets/archetype/styleguide/components/_button_groups.scss +47 -0
  45. data/stylesheets/archetype/styleguide/components/_button_toolbars.scss +17 -0
  46. data/stylesheets/archetype/styleguide/components/_buttons.scss +338 -0
  47. data/stylesheets/archetype/styleguide/components/_canvas.scss +15 -0
  48. data/stylesheets/archetype/styleguide/components/_carets.scss +336 -0
  49. data/stylesheets/archetype/styleguide/components/_closes.scss +63 -0
  50. data/stylesheets/archetype/styleguide/components/_container.scss +27 -0
  51. data/stylesheets/archetype/styleguide/components/_copy.scss +85 -0
  52. data/stylesheets/archetype/styleguide/components/_flyouts.scss +52 -0
  53. data/stylesheets/archetype/styleguide/components/_headings.scss +33 -0
  54. data/stylesheets/archetype/styleguide/components/_headlines.scss +63 -0
  55. data/stylesheets/archetype/styleguide/components/_hovercards.scss +27 -0
  56. data/stylesheets/archetype/styleguide/components/_icons.scss +17 -0
  57. data/stylesheets/archetype/styleguide/components/_identities.scss +34 -0
  58. data/stylesheets/archetype/styleguide/components/_links.scss +66 -0
  59. data/stylesheets/archetype/styleguide/components/_loaders.scss +154 -0
  60. data/stylesheets/archetype/styleguide/components/_menu_items.scss +31 -0
  61. data/stylesheets/archetype/styleguide/components/_module.scss +15 -0
  62. data/stylesheets/archetype/styleguide/components/_pullquotes.scss +29 -0
  63. data/stylesheets/archetype/styleguide/components/_punchcut.scss +18 -0
  64. data/stylesheets/archetype/styleguide/components/_tooltips.scss +28 -0
  65. data/stylesheets/archetype/styleguide/primitives/_animations.scss +17 -0
  66. data/stylesheets/archetype/styleguide/primitives/_dimensions.scss +50 -0
  67. data/stylesheets/archetype/styleguide/primitives/_glyphs.scss +11 -0
  68. data/stylesheets/archetype/styleguide/primitives/_misc.scss +8 -0
  69. data/stylesheets/archetype/styleguide/primitives/_palettes.scss +94 -0
  70. data/stylesheets/archetype/styleguide/primitives/_shadows.scss +23 -0
  71. data/stylesheets/archetype/styleguide/primitives/_sprites.scss +46 -0
  72. data/stylesheets/archetype/styleguide/primitives/_textures.scss +10 -0
  73. data/stylesheets/archetype/styleguide/primitives/_typography.scss +56 -0
  74. data/stylesheets/archetype/util/_debug.scss +40 -0
  75. data/stylesheets/archetype/util/_lists.scss +57 -0
  76. data/stylesheets/archetype/util/_misc.scss +108 -0
  77. data/stylesheets/archetype/util/_rtl.scss +279 -0
  78. data/stylesheets/archetype/util/_spacing.scss +78 -0
  79. data/stylesheets/archetype/util/_styles.scss +466 -0
  80. data/stylesheets/archetype/util/_targeting.scss +210 -0
  81. data/stylesheets/archetype/util/_units.scss +18 -0
  82. data/templates/example/index.html +40 -0
  83. data/templates/example/manifest.rb +13 -0
  84. data/templates/example/screen.scss +99 -0
  85. data/templates/example/vendor/archetype/animations/loaders/large/large.png +0 -0
  86. data/templates/example/vendor/archetype/animations/loaders/large/large_dark.png +0 -0
  87. data/templates/example/vendor/archetype/animations/loaders/large/large_dark_static.png +0 -0
  88. data/templates/example/vendor/archetype/animations/loaders/large/large_static.png +0 -0
  89. data/templates/example/vendor/archetype/animations/loaders/medium/medium.png +0 -0
  90. data/templates/example/vendor/archetype/animations/loaders/medium/medium_dark.png +0 -0
  91. data/templates/example/vendor/archetype/animations/loaders/medium/medium_dark_static.png +0 -0
  92. data/templates/example/vendor/archetype/animations/loaders/medium/medium_static.png +0 -0
  93. data/templates/example/vendor/archetype/animations/loaders/small/small.png +0 -0
  94. data/templates/example/vendor/archetype/animations/loaders/small/small_dark.png +0 -0
  95. data/templates/example/vendor/archetype/animations/loaders/small/small_dark_static.png +0 -0
  96. data/templates/example/vendor/archetype/animations/loaders/small/small_static.png +0 -0
  97. data/templates/example/vendor/archetype/fontawesome-webfont.eot +0 -0
  98. data/templates/example/vendor/archetype/fontawesome-webfont.svg +255 -0
  99. data/templates/example/vendor/archetype/fontawesome-webfont.ttf +0 -0
  100. data/templates/example/vendor/archetype/fontawesome-webfont.woff +0 -0
  101. data/templates/project/manifest.rb +9 -0
  102. data/templates/project/screen.scss +1 -0
  103. data/templates/project/vendor/archetype/animations/loaders/large/large.png +0 -0
  104. data/templates/project/vendor/archetype/animations/loaders/large/large_dark.png +0 -0
  105. data/templates/project/vendor/archetype/animations/loaders/large/large_dark_static.png +0 -0
  106. data/templates/project/vendor/archetype/animations/loaders/large/large_static.png +0 -0
  107. data/templates/project/vendor/archetype/animations/loaders/medium/medium.png +0 -0
  108. data/templates/project/vendor/archetype/animations/loaders/medium/medium_dark.png +0 -0
  109. data/templates/project/vendor/archetype/animations/loaders/medium/medium_dark_static.png +0 -0
  110. data/templates/project/vendor/archetype/animations/loaders/medium/medium_static.png +0 -0
  111. data/templates/project/vendor/archetype/animations/loaders/small/small.png +0 -0
  112. data/templates/project/vendor/archetype/animations/loaders/small/small_dark.png +0 -0
  113. data/templates/project/vendor/archetype/animations/loaders/small/small_dark_static.png +0 -0
  114. data/templates/project/vendor/archetype/animations/loaders/small/small_static.png +0 -0
  115. data/templates/project/vendor/archetype/fontawesome-webfont.eot +0 -0
  116. data/templates/project/vendor/archetype/fontawesome-webfont.svg +255 -0
  117. data/templates/project/vendor/archetype/fontawesome-webfont.ttf +0 -0
  118. data/templates/project/vendor/archetype/fontawesome-webfont.woff +0 -0
  119. data/test/fixtures/stylesheets/archetype/assets/fonts/fontawesome-webfont.eot +0 -0
  120. data/test/fixtures/stylesheets/archetype/assets/fonts/fontawesome-webfont.svg +255 -0
  121. data/test/fixtures/stylesheets/archetype/assets/fonts/fontawesome-webfont.ttf +0 -0
  122. data/test/fixtures/stylesheets/archetype/assets/fonts/fontawesome-webfont.woff +0 -0
  123. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/large/large.png +0 -0
  124. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/large/large_dark.png +0 -0
  125. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/large/large_dark_static.png +0 -0
  126. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/large/large_static.png +0 -0
  127. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/medium/medium.png +0 -0
  128. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/medium/medium_dark.png +0 -0
  129. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/medium/medium_dark_static.png +0 -0
  130. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/medium/medium_static.png +0 -0
  131. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/small/small.png +0 -0
  132. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/small/small_dark.png +0 -0
  133. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/small/small_dark_static.png +0 -0
  134. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/animations/loaders/small/small_static.png +0 -0
  135. data/test/fixtures/stylesheets/archetype/assets/images/vendor/archetype/sprites/hovercard_tip.png +0 -0
  136. data/test/fixtures/stylesheets/archetype/config.rb +19 -0
  137. data/test/fixtures/stylesheets/archetype/expected/b.css +14 -0
  138. data/test/fixtures/stylesheets/archetype/expected/base.css +349 -0
  139. data/test/fixtures/stylesheets/archetype/expected/hacks/ie_pseudo.css +11 -0
  140. data/test/fixtures/stylesheets/archetype/expected/locale.css +23 -0
  141. data/test/fixtures/stylesheets/archetype/expected/styleguide/buttons.css +2091 -0
  142. data/test/fixtures/stylesheets/archetype/expected/styleguide/fallback_styles.css +9 -0
  143. data/test/fixtures/stylesheets/archetype/expected/styleguide/nested_styleguides.css +24 -0
  144. data/test/fixtures/stylesheets/archetype/expected/styleguide/selective_state.css +174 -0
  145. data/test/fixtures/stylesheets/archetype/expected/ui/glyph_icon.css +37 -0
  146. data/test/fixtures/stylesheets/archetype/expected/ui/hide_element.css +8 -0
  147. data/test/fixtures/stylesheets/archetype/expected/ui/stroke.css +17 -0
  148. data/test/fixtures/stylesheets/archetype/expected/ui/triangle.css +35 -0
  149. data/test/fixtures/stylesheets/archetype/expected/utilities/associative.css +9 -0
  150. data/test/fixtures/stylesheets/archetype/expected/utilities/if-set.css +9 -0
  151. data/test/fixtures/stylesheets/archetype/expected/utilities/spacing/horizontal-spacing.css +29 -0
  152. data/test/fixtures/stylesheets/archetype/expected/utilities/spacing/vertical-spacing.css +29 -0
  153. data/test/fixtures/stylesheets/archetype/expected/utilities/styles/filter.css +11 -0
  154. data/test/fixtures/stylesheets/archetype/expected/utilities/styles/font-family.css +16 -0
  155. data/test/fixtures/stylesheets/archetype/expected/utilities/styles/z-index.css +15 -0
  156. data/test/fixtures/stylesheets/archetype/expected/utilities/targeting/target-browser.css +100 -0
  157. data/test/fixtures/stylesheets/archetype/expected/utilities/targeting/target-os.css +55 -0
  158. data/test/fixtures/stylesheets/archetype/source/b.scss +9 -0
  159. data/test/fixtures/stylesheets/archetype/source/base.scss +3 -0
  160. data/test/fixtures/stylesheets/archetype/source/hacks/ie_pseudo.scss +13 -0
  161. data/test/fixtures/stylesheets/archetype/source/locale.scss +43 -0
  162. data/test/fixtures/stylesheets/archetype/source/styleguide/buttons.scss +18 -0
  163. data/test/fixtures/stylesheets/archetype/source/styleguide/fallback_styles.scss +22 -0
  164. data/test/fixtures/stylesheets/archetype/source/styleguide/nested_styleguides.scss +40 -0
  165. data/test/fixtures/stylesheets/archetype/source/styleguide/selective_state.scss +22 -0
  166. data/test/fixtures/stylesheets/archetype/source/ui/glyph_icon.scss +13 -0
  167. data/test/fixtures/stylesheets/archetype/source/ui/hide_element.scss +5 -0
  168. data/test/fixtures/stylesheets/archetype/source/ui/stroke.scss +13 -0
  169. data/test/fixtures/stylesheets/archetype/source/ui/triangle.scss +13 -0
  170. data/test/fixtures/stylesheets/archetype/source/utilities/associative.scss +24 -0
  171. data/test/fixtures/stylesheets/archetype/source/utilities/if-set.scss +16 -0
  172. data/test/fixtures/stylesheets/archetype/source/utilities/spacing/horizontal-spacing.scss +27 -0
  173. data/test/fixtures/stylesheets/archetype/source/utilities/spacing/vertical-spacing.scss +27 -0
  174. data/test/fixtures/stylesheets/archetype/source/utilities/styles/filter.scss +9 -0
  175. data/test/fixtures/stylesheets/archetype/source/utilities/styles/font-family.scss +9 -0
  176. data/test/fixtures/stylesheets/archetype/source/utilities/styles/z-index.scss +18 -0
  177. data/test/fixtures/stylesheets/archetype/source/utilities/targeting/target-browser.scss +70 -0
  178. data/test/fixtures/stylesheets/archetype/source/utilities/targeting/target-os.scss +42 -0
  179. data/test/helpers/diff.rb +49 -0
  180. data/test/helpers/io.rb +36 -0
  181. data/test/helpers/test_case.rb +62 -0
  182. data/test/integrations/archetype_test.rb +126 -0
  183. data/test/test_helper.rb +26 -0
  184. data/test/units/sass_extensions_test.rb +207 -0
  185. metadata +303 -15
@@ -0,0 +1,19 @@
1
+ #
2
+ # This module provides a set of Sass functions for working with Sass::Number
3
+ #
4
+ module Archetype::SassExtensions::Numbers
5
+ #
6
+ # remove the units from a number
7
+ #
8
+ # *Parameters*:
9
+ # - <tt>$number</tt> {Number} the number to remove units from
10
+ # *Returns*:
11
+ # - {Number} the number without units
12
+ #
13
+ def strip_units(number)
14
+ value = 0
15
+ value = number.value.to_f if number.is_a?(Sass::Script::String)
16
+ value = number.value if number.is_a?(Sass::Script::Number)
17
+ return Sass::Script::Number.new(value)
18
+ end
19
+ end
@@ -0,0 +1,406 @@
1
+ require 'archetype/functions/helpers'
2
+ require 'archetype/functions/styleguide_memoizer'
3
+ require 'thread'
4
+
5
+ #
6
+ # This is the magic of Archetype. This module provides the interfaces for constructing,
7
+ # extending, and retrieving reusable UI components
8
+ #
9
+ module Archetype::SassExtensions::Styleguide
10
+
11
+ # :stopdoc:
12
+ INHERIT = 'inherit'
13
+ STYLEGUIDE = 'styleguide'
14
+ DROP = 'drop'
15
+ DEFAULT = 'default'
16
+ REGEX = 'regex'
17
+ SPECIAL = %w(states selectors)
18
+ # these are unique CSS keys that can be exploited to provide fallback functionality by providing a second value
19
+ # e.g color: red; color: rgba(255,0,0, 0.8);
20
+ 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)
21
+ ADDITIVES = FALLBACKS + [DROP, INHERIT, STYLEGUIDE]
22
+ @@archetype_styleguide_mutex = Mutex.new
23
+ # :startdoc:
24
+
25
+ #
26
+ # interface for adding new components to the styleguide structure
27
+ #
28
+ # *Parameters*:
29
+ # - <tt>$id</tt> {String} the component identifier
30
+ # - <tt>$data</tt> {List} the component data object
31
+ # - <tt>$default</tt> {List} the default data object (for extending)
32
+ # - <tt>$theme</tt> {String} the theme to insert the component into
33
+ # - <tt>$force</tt> {Boolean} if true, forcibly insert the component
34
+ # *Returns*:
35
+ # - {Boolean} whether or not the component was added
36
+ #
37
+ def styleguide_add_component(id, data, default = nil, theme = nil, force = false)
38
+ @@archetype_styleguide_mutex.synchronize do
39
+ theme = get_theme(theme)
40
+ components = theme[:components]
41
+ id = helpers.to_str(id)
42
+ # if force was true, we have to invalidate the memoizer
43
+ memoizer.clear(theme[:name]) if force
44
+ # if we already have the component, don't create it again
45
+ return Sass::Script::Bool.new(false) if component_exists(id, theme, nil, force)
46
+ # otherwise add it
47
+ components[id] = helpers.list_to_hash(default, 1, SPECIAL, ADDITIVES).merge(helpers.list_to_hash(data, 1, SPECIAL, ADDITIVES))
48
+ return Sass::Script::Bool.new(true)
49
+ end
50
+ end
51
+ Sass::Script::Functions.declare :styleguide_add_component, [:id, :data]
52
+ Sass::Script::Functions.declare :styleguide_add_component, [:id, :data, :default]
53
+ Sass::Script::Functions.declare :styleguide_add_component, [:id, :data, :default, :theme]
54
+
55
+ #
56
+ # interface for extending an existing components in the styleguide structure
57
+ #
58
+ # *Parameters*:
59
+ # - <tt>$id</tt> {String} the component identifier
60
+ # - <tt>$data</tt> {List} the component data object
61
+ # - <tt>$theme</tt> {String} the theme to insert the component into
62
+ # - <tt>$extension</tt> {String} the name of the extension
63
+ # - <tt>$force</tt> {Boolean} if true, forcibly extend the component
64
+ # *Returns*:
65
+ # - {Boolean} whether or not the component was extended
66
+ #
67
+ def styleguide_extend_component(id, data, theme = nil, extension = nil, force = false)
68
+ @@archetype_styleguide_mutex.synchronize do
69
+ theme = get_theme(theme)
70
+ components = theme[:components]
71
+ id = helpers.to_str(id)
72
+ # if force was set, we'll create a random token for the name
73
+ extension = rand(36**8).to_s(36) if force
74
+ # convert the extension into a hash (if we don't have an extension, compose one out of its data)
75
+ extension = helpers.to_str(extension || data).hash
76
+ extensions = theme[:extensions]
77
+ return Sass::Script::Bool.new(false) if component_exists(id, theme, extension, force)
78
+ extensions.push(extension)
79
+ components[id] = (components[id] ||= Archetype::Hash.new).rmerge(helpers.list_to_hash(data, 1, SPECIAL, ADDITIVES))
80
+ return Sass::Script::Bool.new(true)
81
+ end
82
+ end
83
+ Sass::Script::Functions.declare :styleguide_extend_component, [:id, :data]
84
+ Sass::Script::Functions.declare :styleguide_extend_component, [:id, :data, :theme]
85
+ Sass::Script::Functions.declare :styleguide_extend_component, [:id, :data, :theme, :extension]
86
+
87
+ #
88
+ # check whether or not a component (or a component extension) has already been defined
89
+ #
90
+ # *Parameters*:
91
+ # - <tt>$id</tt> {String} the component identifier
92
+ # - <tt>$data</tt> {List} the component data object
93
+ # - <tt>$theme</tt> {String} the theme to insert the component into
94
+ # - <tt>$extension</tt> {String} the name of the extension
95
+ # - <tt>$force</tt> {Boolean} if true, forcibly extend the component
96
+ # *Returns*:
97
+ # - {Boolean} whether or not the component/extension exists
98
+ #
99
+ def styleguide_component_exists(id, theme = nil, extension = nil, force = false)
100
+ @@archetype_styleguide_mutex.synchronize do
101
+ extension = helpers.to_str(extension).hash if not extension.nil?
102
+ return Sass::Script::Bool.new( component_exists(id, theme, extension, force) )
103
+ end
104
+ end
105
+ Sass::Script::Functions.declare :styleguide_extend_component, [:id]
106
+ Sass::Script::Functions.declare :styleguide_extend_component, [:id, :theme]
107
+ Sass::Script::Functions.declare :styleguide_extend_component, [:id, :theme, :extension]
108
+ Sass::Script::Functions.declare :styleguide_extend_component, [:id, :theme, :extension, :force]
109
+
110
+ #
111
+ # given a description of the component, convert it into CSS
112
+ #
113
+ # *Parameters*:
114
+ # - <tt>$description</tt> {String|List} the description of the component
115
+ # - <tt>$theme</tt> {String} the theme to use
116
+ # *Returns*:
117
+ # - {List} a key-value paired list of styles
118
+ #
119
+ def styleguide(description, state = 'false', theme = nil)
120
+ @@archetype_styleguide_mutex.synchronize do
121
+ # convert it back to a Sass:List and carry on
122
+ return helpers.hash_to_list(get_styles(description, theme, state), 0)
123
+ end
124
+ end
125
+
126
+ #
127
+ # output the CSS differences between components
128
+ #
129
+ # *Parameters*:
130
+ # - <tt>$original</tt> {String|List} the description of the original component
131
+ # - <tt>$other</tt> {String|List} the description of the new component
132
+ # - <tt>$theme</tt> {String} the theme to use
133
+ # *Returns*:
134
+ # - {List} a key-value paired list of styles
135
+ #
136
+ def styleguide_diff(original, other, theme = nil)
137
+ @@archetype_styleguide_mutex.synchronize do
138
+ original = get_styles(original, theme)
139
+ other = get_styles(other, theme)
140
+ diff = original.diff(other)
141
+ return helpers.hash_to_list(diff, 0)
142
+ end
143
+ end
144
+
145
+ private
146
+ def helpers
147
+ @helpers ||= Archetype::Functions::Helpers
148
+ end
149
+ def memoizer
150
+ Archetype::Functions::StyleguideMemoizer
151
+ end
152
+
153
+ #
154
+ # given a sentence, deconstruct it into it's identifier and verbages
155
+ #
156
+ # *Parameters*:
157
+ # - <tt>sentence</tt> {String|List} the sentence describing the component
158
+ # - <tt>theme</tt> {String} the theme to use
159
+ # - <tt>state</tt> {String} the name of a state to return
160
+ # *Returns*:
161
+ # - {Array} an array containing the identifer, modifiers, and a token
162
+ #
163
+ def grammar(sentence, theme = nil, state = 'false')
164
+ theme = get_theme(theme)
165
+ components = theme[:components]
166
+ # get a list of valid ids
167
+ styleguideIds = components.keys
168
+ sentence = sentence.split if sentence.is_a? String
169
+ sentence = sentence.to_a
170
+ id = nil
171
+ modifiers = []
172
+ if not sentence.empty?
173
+ prefix = ''
174
+ order = ''
175
+ # these define various attributes for modifiers (e.g. `button with a shadow`)
176
+ extras = %w(on with without)
177
+ # these are things that are useless to us, so we just leave them out
178
+ ignore = %w(a an also the this that is was it)
179
+ # these are our context switches (e.g. `headline in a button`)
180
+ contexts = %w(in)
181
+ sentence.each do |item|
182
+ item = item.value
183
+ # find the ID
184
+ if id.nil? and styleguideIds.include?(item) and prefix.empty? and order.empty?
185
+ id = item
186
+ # if it's a `context`, we need to increase the depth and reset the prefix
187
+ elsif contexts.include?(item)
188
+ order = "#{item}-#{order}"
189
+ prefix = ''
190
+ # if it's an `extra`, we update the prefix
191
+ elsif extras.include?(item)
192
+ prefix = "#{item}-"
193
+ # finally, check that it's not on the ignore (useless) list. if it is, we just skip over it
194
+ # (maybe this should be the first thing we check?)
195
+ elsif not ignore.include?(item)
196
+ modifiers.push("#{order}#{prefix}#{item}")
197
+ end
198
+ end
199
+ end
200
+ # if there was no id, return a list of valid IDs for reporting
201
+ modifiers = styleguideIds if id.nil?
202
+ # get the list of currenty installed component extensions
203
+ extensions = theme[:extensions] if not id.nil?
204
+ # TODO - low - eoneill: make sure we always want to return unique modifiers
205
+ # i can't think of a case where we wouldn't want to remove dups
206
+ # maybe in the case where we're looking for strict keys on the lookup?
207
+ modifiers = modifiers.uniq
208
+ token = memoizer.tokenize(theme[:name], extensions, id, modifiers, state)
209
+ return id, modifiers, token
210
+ end
211
+
212
+ #
213
+ # interface for extracting styles in the styleguide references
214
+ #
215
+ # *Parameters*:
216
+ # - <tt>id</tt> {String} the component identifier
217
+ # - <tt>modifiers</tt> {Array} the component modifiers
218
+ # - <tt>strict</tt> {Boolean} is it a strict lookup?
219
+ # - <tt>theme</tt> {String} the theme to use
220
+ # - <tt>context</tt> {Hash} the context to work in
221
+ # *Returns*:
222
+ # - {Hash} a hash of the extracted styles
223
+ #
224
+ def extract_styles(id, modifiers, strict = false, theme = nil, context = nil)
225
+ theme = get_theme(theme)
226
+ context ||= theme[:components][id] || Archetype::Hash.new
227
+ modifiers = helpers.to_str(modifiers)
228
+ return Archetype::Hash.new if context.nil? or context.empty?
229
+ # push on the defaults first
230
+ out = (strict ? resolve_dependents(id, context[modifiers], theme[:name], context) : context[DEFAULT]) || Archetype::Hash.new
231
+ out = out.clone
232
+ # if it's not strict, find anything that matched
233
+ if not strict
234
+ modifiers = modifiers.split
235
+ context.each do |key, definition|
236
+ definition = [key, definition]
237
+ modifier = definition[0]
238
+ if modifier != DEFAULT
239
+ match = true
240
+ modifier = modifier.split
241
+ if modifier[0] == REGEX
242
+ # if it's a regex pattern, test if it matches
243
+ match = modifiers.join(' ') =~ /#{modifier[1].gsub(/\A"|"\Z/, '')}/i
244
+ else
245
+ # otherwise, if the modifier isn't in our list of modifiers, it's not valid and just move on
246
+ modifier.each { |i| match = false if not modifiers.include?(i) }
247
+ end
248
+ # if it matched, process it
249
+ out = out.rmerge(resolve_dependents(id, definition[1], theme[:name], nil, out.keys)) if match
250
+ end
251
+ end
252
+ end
253
+ # recompose the special keys and extract any nested/inherited styles
254
+ # this lets us define special states and elements
255
+ SPECIAL.each do |special_key|
256
+ 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?
261
+ end
262
+ end
263
+ # check for nested styleguides
264
+ styleguide = out[STYLEGUIDE]
265
+ if styleguide and not styleguide.empty?
266
+ styles = get_styles(styleguide, theme[:name])
267
+ out.delete(STYLEGUIDE)
268
+ out = styles.rmerge(out)
269
+ end
270
+ return out
271
+ end
272
+
273
+ #
274
+ # resolve any dependent references from the component
275
+ #
276
+ # *Parameters*:
277
+ # - <tt>id</tt> {String} the component identifier
278
+ # - <tt>value</tt> {Hash} the current value
279
+ # - <tt>theme</tt> {String} the theme to use
280
+ # - <tt>context</tt> {Hash} the context to work in
281
+ # - <tt>keys</tt> {Array} list of the external keys
282
+ # *Returns*:
283
+ # - {Hash} a hash of the resolved styles
284
+ #
285
+ def resolve_dependents(id, value, theme = nil, context = nil, keys = nil)
286
+ # we have to create a clone here as the passed in value is volatile and we're performing destructive changes
287
+ value = value.clone
288
+ # check that we're dealing with a hash
289
+ if value.is_a?(Hash)
290
+ # 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
307
+ # check for inheritance
308
+ inherit = value[INHERIT]
309
+ if inherit and not inherit.empty?
310
+ # create a temporary object and extract the nested styles
311
+ tmp = Archetype::Hash.new
312
+ inherit.each { |related| tmp = tmp.rmerge(extract_styles(id, related, true, theme, context)) }
313
+ # remove the inheritance key and update the styles
314
+ value.delete(INHERIT)
315
+ value = tmp.rmerge(value)
316
+ end
317
+ end
318
+ # return whatever we got
319
+ return value
320
+ end
321
+
322
+ #
323
+ # keep a registry of styleguide themes
324
+ #
325
+ # *Parameters*:
326
+ # - <tt>theme</tt> {String} the theme to use
327
+ # *Returns*:
328
+ # - {Hash} the theme
329
+ #
330
+ def get_theme(theme)
331
+ theme_name = helpers.to_str(theme || 'archetype')
332
+ @@styleguide_themes ||= {}
333
+ theme = @@styleguide_themes[theme_name] ||= {}
334
+ theme[:name] ||= theme_name
335
+ theme[:components] ||= {}
336
+ theme[:extensions] ||= []
337
+ return theme
338
+ end
339
+
340
+ #
341
+ # driver method for converting a sentence into a list of styles
342
+ #
343
+ # *Parameters*:
344
+ # - <tt>description</tt> {String|List} the description of the component
345
+ # - <tt>theme</tt> {String} the theme to use
346
+ # - <tt>state</tt> {String} the name of a state to return
347
+ # *Returns*:
348
+ # - {Hash} the styles
349
+ #
350
+ def get_styles(description, theme = nil, state = 'false')
351
+ state = helpers.to_str(state)
352
+ description = description.to_a
353
+ styles = Archetype::Hash.new
354
+ description.each do |sentence|
355
+ # get the grammar from the sentence
356
+ id, modifiers, token = grammar(sentence, theme, state)
357
+ if id
358
+ # check memoizer
359
+ memoized = memoizer.fetch(theme, token)
360
+ if memoized
361
+ styles = styles.rmerge(memoized)
362
+ else
363
+ # fetch additional styles
364
+ extracted = extract_styles(id, modifiers, false, theme)
365
+ # we can delete anything that had a value of `nil` as we won't be outputting those
366
+ extracted.delete_if { |k,v| helpers.is_value(v, :nil) }
367
+ styles = styles.rmerge(extracted)
368
+ memoizer.add(theme, token, extracted)
369
+ end
370
+ elsif not helpers.is_value(sentence, :nil)
371
+ helpers.logger.record(:warning, "[archetype:styleguide:missing_identifier] `#{helpers.to_str(sentence)}` does not contain an identifier. please specify one of: #{modifiers.sort.join(', ')}")
372
+ end
373
+ end
374
+ # now that we've collected all of our styles, if we requested a single state, merge that state upstream
375
+ if state != 'false' and styles['states']
376
+ state = styles['states'][state]
377
+ # remove any nested/special keys
378
+ SPECIAL.each do |special|
379
+ styles.delete(special)
380
+ end
381
+ styles = styles.merge(state) if not (state.nil? or state.empty?)
382
+ end
383
+ return styles
384
+ end
385
+
386
+ #
387
+ # check whether or not a component (or a component extension) has already been defined
388
+ #
389
+ # *Parameters*:
390
+ # - <tt>$id</tt> {String} the component identifier
391
+ # - <tt>$data</tt> {List} the component data object
392
+ # - <tt>$theme</tt> {String} the theme to insert the component into
393
+ # - <tt>$extension</tt> {String} the name of the extension
394
+ # - <tt>$force</tt> {Boolean} if true, forcibly extend the component
395
+ # *Returns*:
396
+ # - {Boolean} whether or not the component/extension exists
397
+ #
398
+ def component_exists(id, theme = nil, extension = nil, force = false)
399
+ status = false
400
+ theme = get_theme(theme) if not theme.is_a? Hash
401
+ id = helpers.to_str(id)
402
+ # determine the status of the component
403
+ status = (extension.nil?) ? (not theme[:components][id].nil?) : theme[:extensions].include?(extension)
404
+ return (status and not force and Compass.configuration.memoize)
405
+ end
406
+ end
@@ -0,0 +1,59 @@
1
+ require 'archetype/functions/helpers'
2
+ require 'thread'
3
+
4
+ #
5
+ # This module provides some UI helper methods.
6
+ #
7
+ module Archetype::SassExtensions::UI
8
+ # :stopdoc:
9
+ @@archetype_ui_mutex = Mutex.new
10
+ # :startdoc:
11
+
12
+ #
13
+ # generate a unique token
14
+ #
15
+ # *Parameters*:
16
+ # - <tt>$prefix</tt> {String} a string to prefix the UID with, `class` and `id` will generate a unique selector
17
+ # *Returns*:
18
+ # - {String} the unique string
19
+ #
20
+ def unique(prefix = '')
21
+ prefix = helpers.to_str(prefix, ' ', :quotes)
22
+ prefix = '.' if prefix == 'class'
23
+ prefix = '#' if prefix == 'id'
24
+ return Sass::Script::String.new("#{prefix}archetype-uid-#{uid}")
25
+ end
26
+
27
+ #
28
+ # parse a CSS content string and format it for injection into innerHTML
29
+ #
30
+ # *Parameters*:
31
+ # - <tt>$content</tt> {String} the CSS content string
32
+ # *Returns*:
33
+ # - {String} the processed string
34
+ #
35
+ def _ie_pseudo_content(content)
36
+ content = helpers.to_str(content)
37
+ # escape &
38
+ content = content.gsub(/\&/, '&amp;')
39
+ # convert char codes (and remove single trailing whitespace if present) (e.g. \2079 -> &#x2079;)
40
+ content = content.gsub(/\\([\da-zA-Z]{4})\s?/, '&#x\1;')
41
+ # escape tags and cleanup quotes
42
+ content = content.gsub(/\</, '&lt;').gsub(/\>/, '&gt;')
43
+ # cleanup quotes
44
+ content = content.gsub(/\A"|"\Z/, '').gsub(/\"/, '\\"')
45
+ return Sass::Script::String.new(content)
46
+ end
47
+
48
+ private
49
+ def helpers
50
+ @helpers ||= Archetype::Functions::Helpers
51
+ end
52
+
53
+ def uid
54
+ @@archetype_ui_mutex.synchronize do
55
+ @@uid ||= 0
56
+ @@uid += 1
57
+ end
58
+ end
59
+ end