sassc 0.0.1

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 (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +24 -0
  8. data/Rakefile +21 -0
  9. data/ext/libsass/.editorconfig +15 -0
  10. data/ext/libsass/.gitattributes +2 -0
  11. data/ext/libsass/.gitignore +61 -0
  12. data/ext/libsass/.travis.yml +38 -0
  13. data/ext/libsass/COPYING +25 -0
  14. data/ext/libsass/INSTALL +1 -0
  15. data/ext/libsass/LICENSE +25 -0
  16. data/ext/libsass/Makefile +223 -0
  17. data/ext/libsass/Makefile.am +145 -0
  18. data/ext/libsass/Readme.md +93 -0
  19. data/ext/libsass/appveyor.yml +76 -0
  20. data/ext/libsass/ast.cpp +581 -0
  21. data/ext/libsass/ast.hpp +1949 -0
  22. data/ext/libsass/ast_def_macros.hpp +16 -0
  23. data/ext/libsass/ast_factory.hpp +87 -0
  24. data/ext/libsass/ast_fwd_decl.hpp +72 -0
  25. data/ext/libsass/b64/cencode.h +32 -0
  26. data/ext/libsass/b64/encode.h +77 -0
  27. data/ext/libsass/backtrace.hpp +81 -0
  28. data/ext/libsass/base64vlq.cpp +43 -0
  29. data/ext/libsass/base64vlq.hpp +28 -0
  30. data/ext/libsass/bind.cpp +187 -0
  31. data/ext/libsass/bind.hpp +18 -0
  32. data/ext/libsass/cencode.c +102 -0
  33. data/ext/libsass/color_names.hpp +324 -0
  34. data/ext/libsass/configure.ac +130 -0
  35. data/ext/libsass/constants.cpp +144 -0
  36. data/ext/libsass/constants.hpp +145 -0
  37. data/ext/libsass/context.cpp +507 -0
  38. data/ext/libsass/context.hpp +150 -0
  39. data/ext/libsass/contextualize.cpp +157 -0
  40. data/ext/libsass/contextualize.hpp +65 -0
  41. data/ext/libsass/copy_c_str.cpp +13 -0
  42. data/ext/libsass/copy_c_str.hpp +5 -0
  43. data/ext/libsass/debug.hpp +39 -0
  44. data/ext/libsass/environment.hpp +75 -0
  45. data/ext/libsass/error_handling.cpp +28 -0
  46. data/ext/libsass/error_handling.hpp +28 -0
  47. data/ext/libsass/eval.cpp +1149 -0
  48. data/ext/libsass/eval.hpp +80 -0
  49. data/ext/libsass/expand.cpp +430 -0
  50. data/ext/libsass/expand.hpp +77 -0
  51. data/ext/libsass/extconf.rb +6 -0
  52. data/ext/libsass/extend.cpp +1962 -0
  53. data/ext/libsass/extend.hpp +50 -0
  54. data/ext/libsass/file.cpp +291 -0
  55. data/ext/libsass/file.hpp +18 -0
  56. data/ext/libsass/functions.cpp +1565 -0
  57. data/ext/libsass/functions.hpp +187 -0
  58. data/ext/libsass/inspect.cpp +727 -0
  59. data/ext/libsass/inspect.hpp +108 -0
  60. data/ext/libsass/json.cpp +1411 -0
  61. data/ext/libsass/json.hpp +117 -0
  62. data/ext/libsass/kwd_arg_macros.hpp +23 -0
  63. data/ext/libsass/m4/.gitkeep +0 -0
  64. data/ext/libsass/mapping.hpp +17 -0
  65. data/ext/libsass/memory_manager.hpp +54 -0
  66. data/ext/libsass/node.cpp +251 -0
  67. data/ext/libsass/node.hpp +122 -0
  68. data/ext/libsass/operation.hpp +153 -0
  69. data/ext/libsass/output_compressed.cpp +401 -0
  70. data/ext/libsass/output_compressed.hpp +95 -0
  71. data/ext/libsass/output_nested.cpp +364 -0
  72. data/ext/libsass/output_nested.hpp +108 -0
  73. data/ext/libsass/parser.cpp +2016 -0
  74. data/ext/libsass/parser.hpp +264 -0
  75. data/ext/libsass/paths.hpp +69 -0
  76. data/ext/libsass/position.hpp +22 -0
  77. data/ext/libsass/posix/getopt.c +562 -0
  78. data/ext/libsass/posix/getopt.h +95 -0
  79. data/ext/libsass/prelexer.cpp +688 -0
  80. data/ext/libsass/prelexer.hpp +513 -0
  81. data/ext/libsass/remove_placeholders.cpp +59 -0
  82. data/ext/libsass/remove_placeholders.hpp +43 -0
  83. data/ext/libsass/res/resource.rc +35 -0
  84. data/ext/libsass/sass.cpp +33 -0
  85. data/ext/libsass/sass.h +60 -0
  86. data/ext/libsass/sass2scss.cpp +834 -0
  87. data/ext/libsass/sass2scss.h +110 -0
  88. data/ext/libsass/sass_context.cpp +709 -0
  89. data/ext/libsass/sass_context.h +120 -0
  90. data/ext/libsass/sass_functions.cpp +137 -0
  91. data/ext/libsass/sass_functions.h +90 -0
  92. data/ext/libsass/sass_interface.cpp +277 -0
  93. data/ext/libsass/sass_interface.h +97 -0
  94. data/ext/libsass/sass_util.cpp +136 -0
  95. data/ext/libsass/sass_util.hpp +259 -0
  96. data/ext/libsass/sass_values.cpp +337 -0
  97. data/ext/libsass/sass_values.h +124 -0
  98. data/ext/libsass/script/bootstrap +10 -0
  99. data/ext/libsass/script/branding +10 -0
  100. data/ext/libsass/script/ci-build-libsass +72 -0
  101. data/ext/libsass/script/ci-install-compiler +4 -0
  102. data/ext/libsass/script/ci-install-deps +19 -0
  103. data/ext/libsass/script/ci-report-coverage +25 -0
  104. data/ext/libsass/script/coveralls-debug +32 -0
  105. data/ext/libsass/script/spec +5 -0
  106. data/ext/libsass/script/tap-driver +652 -0
  107. data/ext/libsass/script/tap-runner +1 -0
  108. data/ext/libsass/source_map.cpp +133 -0
  109. data/ext/libsass/source_map.hpp +46 -0
  110. data/ext/libsass/subset_map.hpp +145 -0
  111. data/ext/libsass/support/libsass.pc.in +11 -0
  112. data/ext/libsass/test-driver +127 -0
  113. data/ext/libsass/test/test_node.cpp +98 -0
  114. data/ext/libsass/test/test_paths.cpp +29 -0
  115. data/ext/libsass/test/test_selector_difference.cpp +28 -0
  116. data/ext/libsass/test/test_specificity.cpp +28 -0
  117. data/ext/libsass/test/test_subset_map.cpp +472 -0
  118. data/ext/libsass/test/test_superselector.cpp +71 -0
  119. data/ext/libsass/test/test_unification.cpp +33 -0
  120. data/ext/libsass/to_c.cpp +61 -0
  121. data/ext/libsass/to_c.hpp +44 -0
  122. data/ext/libsass/to_string.cpp +29 -0
  123. data/ext/libsass/to_string.hpp +32 -0
  124. data/ext/libsass/token.hpp +32 -0
  125. data/ext/libsass/units.cpp +54 -0
  126. data/ext/libsass/units.hpp +10 -0
  127. data/ext/libsass/utf8.h +34 -0
  128. data/ext/libsass/utf8/checked.h +327 -0
  129. data/ext/libsass/utf8/core.h +329 -0
  130. data/ext/libsass/utf8/unchecked.h +228 -0
  131. data/ext/libsass/utf8_string.cpp +102 -0
  132. data/ext/libsass/utf8_string.hpp +36 -0
  133. data/ext/libsass/util.cpp +189 -0
  134. data/ext/libsass/util.hpp +26 -0
  135. data/ext/libsass/win/libsass.filters +291 -0
  136. data/ext/libsass/win/libsass.sln +28 -0
  137. data/ext/libsass/win/libsass.vcxproj +255 -0
  138. data/lib/sassc.rb +6 -0
  139. data/lib/sassc/engine.rb +13 -0
  140. data/lib/sassc/native.rb +44 -0
  141. data/lib/sassc/native/native_context_api.rb +140 -0
  142. data/lib/sassc/native/native_functions_api.rb +41 -0
  143. data/lib/sassc/native/sass_input_style.rb +11 -0
  144. data/lib/sassc/native/sass_output_style.rb +10 -0
  145. data/lib/sassc/native/sass_value.rb +95 -0
  146. data/lib/sassc/native/string_list.rb +8 -0
  147. data/lib/sassc/version.rb +3 -0
  148. data/sassc.gemspec +43 -0
  149. data/test/smoke_test.rb +171 -0
  150. data/test/test_helper.rb +4 -0
  151. metadata +281 -0
@@ -0,0 +1,97 @@
1
+ #ifndef SASS_C_INTERFACE
2
+ #define SASS_C_INTERFACE
3
+
4
+ #include <stddef.h>
5
+ #include <stdbool.h>
6
+ #include "sass.h"
7
+
8
+ #ifdef __cplusplus
9
+ extern "C" {
10
+ #endif
11
+
12
+
13
+ // Please ensure there are no null values.
14
+ // Thar be dragons.
15
+ struct sass_options {
16
+ // Output style for the generated css code
17
+ // A value from above SASS_STYLE_* constants
18
+ int output_style;
19
+ // If you want inline source comments
20
+ bool source_comments;
21
+ // Path to source map file
22
+ // Enables the source map generating
23
+ // Used to create sourceMappingUrl
24
+ const char* source_map_file;
25
+ // Disable sourceMappingUrl in css output
26
+ bool omit_source_map_url;
27
+ // embed sourceMappingUrl as data uri
28
+ bool source_map_embed;
29
+ // embed include contents in maps
30
+ bool source_map_contents;
31
+ // Treat source_string as sass (as opposed to scss)
32
+ bool is_indented_syntax_src;
33
+ // Colon-separated list of paths
34
+ // Semicolon-separated on Windows
35
+ const char* include_paths;
36
+ // For the image-url Sass function
37
+ const char* image_path;
38
+ // Precision for outputting fractional numbers
39
+ int precision;
40
+ };
41
+
42
+ struct sass_context {
43
+ const char* input_path;
44
+ const char* output_path;
45
+ const char* source_string;
46
+ char* output_string;
47
+ char* source_map_string;
48
+ struct sass_options options;
49
+ int error_status;
50
+ char* error_message;
51
+ Sass_C_Function_List c_functions;
52
+ char** included_files;
53
+ int num_included_files;
54
+ };
55
+
56
+ struct sass_file_context {
57
+ const char* input_path;
58
+ const char* output_path;
59
+ char* output_string;
60
+ char* source_map_string;
61
+ struct sass_options options;
62
+ int error_status;
63
+ char* error_message;
64
+ Sass_C_Function_List c_functions;
65
+ char** included_files;
66
+ int num_included_files;
67
+ };
68
+
69
+ struct sass_folder_context {
70
+ const char* search_path;
71
+ const char* output_path;
72
+ struct sass_options options;
73
+ int error_status;
74
+ char* error_message;
75
+ Sass_C_Function_List c_functions;
76
+ char** included_files;
77
+ int num_included_files;
78
+ };
79
+
80
+ struct sass_context* sass_new_context (void);
81
+ struct sass_file_context* sass_new_file_context (void);
82
+ struct sass_folder_context* sass_new_folder_context (void);
83
+
84
+ void sass_free_context (struct sass_context* ctx);
85
+ void sass_free_file_context (struct sass_file_context* ctx);
86
+ void sass_free_folder_context(struct sass_folder_context* ctx);
87
+
88
+ int sass_compile (struct sass_context* ctx);
89
+ int sass_compile_file (struct sass_file_context* ctx);
90
+ int sass_compile_folder (struct sass_folder_context* ctx);
91
+
92
+
93
+ #ifdef __cplusplus
94
+ }
95
+ #endif
96
+
97
+ #endif
@@ -0,0 +1,136 @@
1
+ #ifndef SASS_AST
2
+ #include "node.hpp"
3
+ #endif
4
+
5
+ #include "to_string.hpp"
6
+
7
+
8
+ namespace Sass {
9
+
10
+
11
+ /*
12
+ This is the equivalent of ruby's Sass::Util.paths.
13
+
14
+ # Return an array of all possible paths through the given arrays.
15
+ #
16
+ # @param arrs [NodeCollection<NodeCollection<Node>>]
17
+ # @return [NodeCollection<NodeCollection<Node>>]
18
+ #
19
+ # @example
20
+ # paths([[1, 2], [3, 4], [5]]) #=>
21
+ # # [[1, 3, 5],
22
+ # # [2, 3, 5],
23
+ # # [1, 4, 5],
24
+ # # [2, 4, 5]]
25
+
26
+ The following is the modified version of the ruby code that was more portable to C++. You
27
+ should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
28
+
29
+ def paths(arrs)
30
+ // I changed the inject and maps to an iterative approach to make it easier to implement in C++
31
+ loopStart = [[]]
32
+
33
+ for arr in arrs do
34
+ permutations = []
35
+ for e in arr do
36
+ for path in loopStart do
37
+ permutations.push(path + [e])
38
+ end
39
+ end
40
+ loopStart = permutations
41
+ end
42
+ end
43
+ */
44
+ Node paths(const Node& arrs, Context& ctx) {
45
+ To_String to_string;
46
+
47
+ Node loopStart = Node::createCollection();
48
+ loopStart.collection()->push_back(Node::createCollection());
49
+
50
+ for (NodeDeque::iterator arrsIter = arrs.collection()->begin(), arrsEndIter = arrs.collection()->end();
51
+ arrsIter != arrsEndIter; ++arrsIter) {
52
+
53
+ Node& arr = *arrsIter;
54
+
55
+ Node permutations = Node::createCollection();
56
+
57
+ for (NodeDeque::iterator arrIter = arr.collection()->begin(), arrIterEnd = arr.collection()->end();
58
+ arrIter != arrIterEnd; ++arrIter) {
59
+
60
+ Node& e = *arrIter;
61
+
62
+ for (NodeDeque::iterator loopStartIter = loopStart.collection()->begin(), loopStartIterEnd = loopStart.collection()->end();
63
+ loopStartIter != loopStartIterEnd; ++loopStartIter) {
64
+
65
+ Node& path = *loopStartIter;
66
+
67
+ Node newPermutation = Node::createCollection();
68
+ newPermutation.plus(path);
69
+ newPermutation.collection()->push_back(e);
70
+
71
+ permutations.collection()->push_back(newPermutation);
72
+ }
73
+ }
74
+
75
+ loopStart = permutations;
76
+ }
77
+
78
+ return loopStart;
79
+ }
80
+
81
+
82
+ /*
83
+ This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
84
+ Sass::Util.flatten requires the number of levels to flatten, while
85
+ [].flatten doesn't and will flatten the entire array. This function
86
+ supports both.
87
+
88
+ # Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
89
+ #
90
+ # @param arr [NodeCollection] The array to flatten
91
+ # @param n [int] The number of levels to flatten
92
+ # @return [NodeCollection] The flattened array
93
+
94
+ The following is the modified version of the ruby code that was more portable to C++. You
95
+ should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
96
+
97
+ def flatten(arr, n = -1)
98
+ if n != -1 and n == 0 then
99
+ return arr
100
+ end
101
+
102
+ flattened = []
103
+
104
+ for e in arr do
105
+ if e.is_a?(Array) then
106
+ flattened.concat(flatten(e, n - 1))
107
+ else
108
+ flattened << e
109
+ end
110
+ end
111
+
112
+ return flattened
113
+ end
114
+ */
115
+ Node flatten(const Node& arr, Context& ctx, int n = -1) {
116
+ if (n != -1 && n == 0) {
117
+ return arr;
118
+ }
119
+
120
+ Node flattened = Node::createCollection();
121
+
122
+ for (NodeDeque::iterator iter = arr.collection()->begin(), iterEnd = arr.collection()->end();
123
+ iter != iterEnd; iter++) {
124
+ Node& e = *iter;
125
+
126
+ if (e.isCollection()) {
127
+ Node recurseFlattened = flatten(e, ctx, n - 1);
128
+ flattened.collection()->insert(flattened.collection()->end(), recurseFlattened.collection()->begin(), recurseFlattened.collection()->end());
129
+ } else {
130
+ flattened.collection()->push_back(e);
131
+ }
132
+ }
133
+
134
+ return flattened;
135
+ }
136
+ }
@@ -0,0 +1,259 @@
1
+ #include <deque>
2
+ #include <iostream>
3
+
4
+ #ifndef SASS_AST
5
+ #include "ast.hpp"
6
+ #endif
7
+
8
+ #include "node.hpp"
9
+ #include "debug.hpp"
10
+
11
+
12
+ namespace Sass {
13
+
14
+
15
+ using namespace std;
16
+
17
+
18
+ /*
19
+ This is for ports of functions in the Sass:Util module.
20
+ */
21
+
22
+
23
+ /*
24
+ # Return a Node collection of all possible paths through the given Node collection of Node collections.
25
+ #
26
+ # @param arrs [NodeCollection<NodeCollection<Node>>]
27
+ # @return [NodeCollection<NodeCollection<Node>>]
28
+ #
29
+ # @example
30
+ # paths([[1, 2], [3, 4], [5]]) #=>
31
+ # # [[1, 3, 5],
32
+ # # [2, 3, 5],
33
+ # # [1, 4, 5],
34
+ # # [2, 4, 5]]
35
+ */
36
+ Node paths(const Node& arrs, Context& ctx);
37
+
38
+
39
+ /*
40
+ This class is a default implementation of a Node comparator that can be passed to the lcs function below.
41
+ It uses operator== for equality comparision. It then returns one if the Nodes are equal.
42
+ */
43
+ class DefaultLcsComparator {
44
+ public:
45
+ bool operator()(const Node& one, const Node& two, Node& out) const {
46
+ // TODO: Is this the correct C++ interpretation?
47
+ // block ||= proc {|a, b| a == b && a}
48
+ if (one == two) {
49
+ out = one;
50
+ return true;
51
+ }
52
+
53
+ return false;
54
+ }
55
+ };
56
+
57
+
58
+ typedef vector<vector<int> > LCSTable;
59
+
60
+
61
+ /*
62
+ This is the equivalent of ruby's Sass::Util.lcs_backtrace.
63
+
64
+ # Computes a single longest common subsequence for arrays x and y.
65
+ # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS
66
+ */
67
+ template<typename ComparatorType>
68
+ Node lcs_backtrace(const LCSTable& c, const Node& x, const Node& y, int i, int j, const ComparatorType& comparator) {
69
+ DEBUG_PRINTLN(LCS, "LCSBACK: X=" << x << " Y=" << y << " I=" << i << " J=" << j)
70
+
71
+ if (i == 0 || j == 0) {
72
+ DEBUG_PRINTLN(LCS, "RETURNING EMPTY")
73
+ return Node::createCollection();
74
+ }
75
+
76
+ NodeDeque& xChildren = *(x.collection());
77
+ NodeDeque& yChildren = *(y.collection());
78
+
79
+ Node compareOut = Node::createNil();
80
+ if (comparator(xChildren[i], yChildren[j], compareOut)) {
81
+ DEBUG_PRINTLN(LCS, "RETURNING AFTER ELEM COMPARE")
82
+ Node result = lcs_backtrace(c, x, y, i - 1, j - 1, comparator);
83
+ result.collection()->push_back(compareOut);
84
+ return result;
85
+ }
86
+
87
+ if (c[i][j - 1] > c[i - 1][j]) {
88
+ DEBUG_PRINTLN(LCS, "RETURNING AFTER TABLE COMPARE")
89
+ return lcs_backtrace(c, x, y, i, j - 1, comparator);
90
+ }
91
+
92
+ DEBUG_PRINTLN(LCS, "FINAL RETURN")
93
+ return lcs_backtrace(c, x, y, i - 1, j, comparator);
94
+ }
95
+
96
+
97
+ /*
98
+ This is the equivalent of ruby's Sass::Util.lcs_table.
99
+
100
+ # Calculates the memoization table for the Least Common Subsequence algorithm.
101
+ # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS
102
+ */
103
+ template<typename ComparatorType>
104
+ void lcs_table(const Node& x, const Node& y, const ComparatorType& comparator, LCSTable& out) {
105
+ DEBUG_PRINTLN(LCS, "LCSTABLE: X=" << x << " Y=" << y)
106
+
107
+ NodeDeque& xChildren = *(x.collection());
108
+ NodeDeque& yChildren = *(y.collection());
109
+
110
+ LCSTable c(xChildren.size(), vector<int>(yChildren.size()));
111
+
112
+ // These shouldn't be necessary since the vector will be initialized to 0 already.
113
+ // x.size.times {|i| c[i][0] = 0}
114
+ // y.size.times {|j| c[0][j] = 0}
115
+
116
+ for (size_t i = 1; i < xChildren.size(); i++) {
117
+ for (size_t j = 1; j < yChildren.size(); j++) {
118
+ Node compareOut = Node::createNil();
119
+
120
+ if (comparator(xChildren[i], yChildren[j], compareOut)) {
121
+ c[i][j] = c[i - 1][j - 1] + 1;
122
+ } else {
123
+ c[i][j] = max(c[i][j - 1], c[i - 1][j]);
124
+ }
125
+ }
126
+ }
127
+
128
+ out = c;
129
+ }
130
+
131
+
132
+ /*
133
+ This is the equivalent of ruby's Sass::Util.lcs.
134
+
135
+ # Computes a single longest common subsequence for `x` and `y`.
136
+ # If there are more than one longest common subsequences,
137
+ # the one returned is that which starts first in `x`.
138
+
139
+ # @param x [NodeCollection]
140
+ # @param y [NodeCollection]
141
+ # @comparator An equality check between elements of `x` and `y`.
142
+ # @return [NodeCollection] The LCS
143
+
144
+ http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
145
+ */
146
+ template<typename ComparatorType>
147
+ Node lcs(Node& x, Node& y, const ComparatorType& comparator, Context& ctx) {
148
+ DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
149
+
150
+ Node newX = Node::createCollection();
151
+ newX.collection()->push_back(Node::createNil());
152
+ newX.plus(x);
153
+
154
+ Node newY = Node::createCollection();
155
+ newY.collection()->push_back(Node::createNil());
156
+ newY.plus(y);
157
+
158
+ LCSTable table;
159
+ lcs_table(newX, newY, comparator, table);
160
+
161
+ return lcs_backtrace(table, newX, newY, static_cast<int>(newX.collection()->size()) - 1, static_cast<int>(newY.collection()->size()) - 1, comparator);
162
+ }
163
+
164
+
165
+ /*
166
+ This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
167
+ Sass::Util.flatten requires the number of levels to flatten, while
168
+ [].flatten doesn't and will flatten the entire array. This function
169
+ supports both.
170
+
171
+ # Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
172
+ #
173
+ # @param arr [NodeCollection] The array to flatten
174
+ # @param n [int] The number of levels to flatten
175
+ # @return [NodeCollection] The flattened array
176
+ */
177
+ Node flatten(const Node& arr, Context& ctx, int n = -1);
178
+
179
+
180
+ /*
181
+ This is the equivalent of ruby's Sass::Util.group_by_to_a.
182
+
183
+ # Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
184
+ # order. Unlike [#hash_to_a], the resulting order isn't sorted key order;
185
+ # instead, it's the same order as `#group_by` has under Ruby 1.9 (key
186
+ # appearance order).
187
+ #
188
+ # @param enum [Enumerable]
189
+ # @return [Array<[Object, Array]>] An array of pairs.
190
+
191
+ TODO: update @param and @return once I know what those are.
192
+
193
+ The following is the modified version of the ruby code that was more portable to C++. You
194
+ should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
195
+
196
+ def group_by_to_a(enum, &block)
197
+ order = {}
198
+
199
+ arr = []
200
+
201
+ grouped = {}
202
+
203
+ for e in enum do
204
+ key = block[e]
205
+ unless order.include?(key)
206
+ order[key] = order.size
207
+ end
208
+
209
+ if not grouped.has_key?(key) then
210
+ grouped[key] = [e]
211
+ else
212
+ grouped[key].push(e)
213
+ end
214
+ end
215
+
216
+ grouped.each do |key, vals|
217
+ arr[order[key]] = [key, vals]
218
+ end
219
+
220
+ arr
221
+ end
222
+
223
+ */
224
+ template<typename EnumType, typename KeyType, typename KeyFunctorType>
225
+ void group_by_to_a(vector<EnumType>& enumeration, KeyFunctorType& keyFunc, vector<pair<KeyType, vector<EnumType> > >& arr /*out*/) {
226
+
227
+ map<unsigned int, KeyType> order;
228
+
229
+ map<KeyType, vector<EnumType> > grouped;
230
+
231
+ for (typename vector<EnumType>::iterator enumIter = enumeration.begin(), enumIterEnd = enumeration.end(); enumIter != enumIterEnd; enumIter++) {
232
+ EnumType& e = *enumIter;
233
+
234
+ KeyType key = keyFunc(e);
235
+
236
+ if (grouped.find(key) == grouped.end()) {
237
+ order.insert(make_pair(order.size(), key));
238
+
239
+ vector<EnumType> newCollection;
240
+ newCollection.push_back(e);
241
+ grouped.insert(make_pair(key, newCollection));
242
+ } else {
243
+ vector<EnumType>& collection = grouped.at(key);
244
+ collection.push_back(e);
245
+ }
246
+ }
247
+
248
+ for (unsigned int index = 0; index < order.size(); index++) {
249
+ KeyType& key = order.at(index);
250
+ vector<EnumType>& values = grouped.at(key);
251
+
252
+ pair<KeyType, vector<EnumType> > grouping = make_pair(key, values);
253
+
254
+ arr.push_back(grouping);
255
+ }
256
+ }
257
+
258
+
259
+ }