SassyJSON 1.0.11 → 1.1.0

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.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # Changelog
2
2
 
3
+ * `1.1.0`: adding the ability to import a JSON file
3
4
  * `1.0.11`: fixing an issue with scientific number parsing
4
5
  * `1.0.10`: improving number and string helpers
5
6
  * `1.0.9`: fixing a bug in `_find-exponent`
data/README.md CHANGED
@@ -26,7 +26,9 @@ npm install sassyjson --save-dev
26
26
 
27
27
  ### Sass
28
28
 
29
- If you only want to play around the code without cloning the repo or using npm, you can find a [single file](https://github.com/HugoGiraudel/SassyJSON/blob/master/dist/_SassyJSON.scss) containing the whole API in the [dist](https://github.com/HugoGiraudel/SassyJSON/tree/master/dist) folder. You can copy its content directly into [Sassmeister](http://sassmeister.com/) to play with the code.
29
+ If you only want to play around the code without cloning the repo or using npm, you can find a [single file](https://github.com/HugoGiraudel/SassyJSON/blob/master/dist/_SassyJSON.scss) containing the whole API in the [dist](https://github.com/HugoGiraudel/SassyJSON/tree/master/dist) folder.
30
+
31
+ Also, SassyJSON is available at [Sassmeister](http://sassmeister.com/).
30
32
 
31
33
  ## Example
32
34
 
@@ -69,6 +71,20 @@ $json-decode: json-decode('{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a":
69
71
  // ("a": 1 2 ("b": 1), "b": #444444 false ("a": 1, "b": "test"), "c": 2 3 4 "string")
70
72
  ```
71
73
 
74
+ ## Importing and decoding a JSON file
75
+
76
+ To importe and decode an external `.json` file directly into a Sass variable:
77
+
78
+ ``` scss
79
+ @import 'relative/path/to/file.json?variable-name'
80
+ // Do something with $variable-name
81
+ ```
82
+
83
+ **Important:**
84
+
85
+ * the path to the JSON file is relative to importing file
86
+ * the get parameter is the variable name to use it in Sass
87
+
72
88
  ## Requirements
73
89
 
74
90
  All you need is a clean version of Sass 3.3. Otherwise it's just pure Sass madness.
@@ -0,0 +1,229 @@
1
+ require 'sass'
2
+
3
+
4
+ # Monkey Path Sass
5
+ # Adapted from: https://github.com/chriseppstein/sass-css-importer
6
+ class Sass::Engine
7
+ alias initialize_without_json_importer initialize
8
+
9
+ def initialize(template, options={})
10
+ initialize_without_json_importer(template, options)
11
+
12
+ json_importer = self.options[:load_paths].find {|lp| lp.is_a?(Sass::Importers::JsonImporter) }
13
+
14
+ unless json_importer
15
+ root = File.dirname(options[:filename] || ".")
16
+ self.options[:load_paths] << Sass::Importers::JsonImporter.new(root)
17
+ end
18
+ end
19
+ end
20
+
21
+ module Sass
22
+ module Importers
23
+ # The default importer, used for any strings found in the load path.
24
+ # Simply loads Sass files from the filesystem using the default logic.
25
+ class JsonImporter < Base
26
+
27
+ attr_accessor :root
28
+
29
+ # Creates a new filesystem importer that imports files relative to a given path.
30
+ #
31
+ # @param root [String] The root path.
32
+ # This importer will import files relative to this path.
33
+ def initialize(root)
34
+ @root = File.expand_path(root)
35
+ @same_name_warnings = Set.new
36
+ end
37
+
38
+ # Enable watching of json files in Sass 3.3+
39
+ def watched_directories
40
+ [root]
41
+ end
42
+
43
+ # Enable watching of json files in Sass 3.3+
44
+ def watched_file?(file)
45
+ file.start_with?(root+File::SEPARATOR) && File.extname(file) == ".json"
46
+ end
47
+ # @see Base#find_relative
48
+ def find_relative(name, base, options)
49
+ _find(File.dirname(base), name, options)
50
+ end
51
+
52
+ # @see Base#find
53
+ def find(name, options)
54
+ _find(@root, name, options)
55
+ end
56
+
57
+ # @see Base#mtime
58
+ def mtime(name, options)
59
+ name = strip_varname(name);
60
+ file, _ = Sass::Util.destructure(find_real_file(@root, name, options))
61
+ File.mtime(file) if file
62
+ rescue Errno::ENOENT
63
+ nil
64
+ end
65
+
66
+ # @see Base#key
67
+ def key(name, options)
68
+ name = strip_varname(name);
69
+ [self.class.name + ":" + File.dirname(File.expand_path(name)),
70
+ File.basename(name)]
71
+ end
72
+
73
+ # @see Base#to_s
74
+ def to_s
75
+ @root
76
+ end
77
+
78
+ def hash
79
+ @root.hash
80
+ end
81
+
82
+ def eql?(other)
83
+ root.eql?(other.root)
84
+ end
85
+
86
+ protected
87
+
88
+ # If a full uri is passed, this removes the root from it
89
+ # otherwise returns the name unchanged
90
+ def remove_root(name)
91
+ if name.index(@root + "/") == 0
92
+ name[(@root.length + 1)..-1]
93
+ else
94
+ name
95
+ end
96
+ end
97
+
98
+ # A hash from file extensions to the syntaxes for those extensions.
99
+ # The syntaxes must be `:sass` or `:scss`.
100
+ #
101
+ # This can be overridden by subclasses that want normal filesystem importing
102
+ # with unusual extensions.
103
+ #
104
+ # @return [{String => Symbol}]
105
+ def extensions
106
+ {'json' => :scss}
107
+ end
108
+
109
+ # Given an `@import`ed path, returns an array of possible
110
+ # on-disk filenames and their corresponding syntaxes for that path.
111
+ #
112
+ # @param name [String] The filename.
113
+ # @return [Array(String, Symbol)] An array of pairs.
114
+ # The first element of each pair is a filename to look for;
115
+ # the second element is the syntax that file would be in (`:sass` or `:scss`).
116
+ def possible_files(name)
117
+ name = escape_glob_characters(name)
118
+ dirname, basename, extname = split(name)
119
+ sorted_exts = extensions.sort
120
+ syntax = extensions[extname]
121
+
122
+ if syntax
123
+ ret = [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]]
124
+ else
125
+ ret = sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
126
+ end
127
+
128
+ # JRuby chokes when trying to import files from JARs when the path starts with './'.
129
+ ret.map {|f, s| [f.sub(%r{^\./}, ''), s]}
130
+ end
131
+
132
+ def escape_glob_characters(name)
133
+ name.gsub(/[\*\[\]\{\}\?]/) do |char|
134
+ "\\#{char}"
135
+ end
136
+ end
137
+
138
+ REDUNDANT_DIRECTORY = %r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}
139
+ # Given a base directory and an `@import`ed name,
140
+ # finds an existant file that matches the name.
141
+ #
142
+ # @param dir [String] The directory relative to which to search.
143
+ # @param name [String] The filename to search for.
144
+ # @return [(String, Symbol)] A filename-syntax pair.
145
+ def find_real_file(dir, name, options)
146
+ # on windows 'dir' can be in native File::ALT_SEPARATOR form
147
+ dir = dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
148
+
149
+ found = possible_files(remove_root(name)).map do |f, s|
150
+ path = (dir == "." || Pathname.new(f).absolute?) ? f : "#{escape_glob_characters(dir)}/#{f}"
151
+ Dir[path].map do |full_path|
152
+ full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
153
+ [Pathname.new(full_path).cleanpath.to_s, s]
154
+ end
155
+ end
156
+ found = Sass::Util.flatten(found, 1)
157
+ return if found.empty?
158
+
159
+ if found.size > 1 && !@same_name_warnings.include?(found.first.first)
160
+ found.each {|(f, _)| @same_name_warnings << f}
161
+ relative_to = Pathname.new(dir)
162
+ if options[:_line]
163
+ # If _line exists, we're here due to an actual import in an
164
+ # import_node and we want to print a warning for a user writing an
165
+ # ambiguous import.
166
+ candidates = found.map {|(f, _)| " " + Pathname.new(f).relative_path_from(relative_to).to_s}.join("\n")
167
+ Sass::Util.sass_warn <<WARNING
168
+ WARNING: On line #{options[:_line]}#{" of #{options[:filename]}" if options[:filename]}:
169
+ It's not clear which file to import for '@import "#{name}"'.
170
+ Candidates:
171
+ #{candidates}
172
+ For now I'll choose #{File.basename found.first.first}.
173
+ This will be an error in future versions of Sass.
174
+ WARNING
175
+ else
176
+ # Otherwise, we're here via StalenessChecker, and we want to print a
177
+ # warning for a user running `sass --watch` with two ambiguous files.
178
+ candidates = found.map {|(f, _)| " " + File.basename(f)}.join("\n")
179
+ Sass::Util.sass_warn <<WARNING
180
+ WARNING: In #{File.dirname(name)}:
181
+ There are multiple files that match the name "#{File.basename(name)}":
182
+ #{candidates}
183
+ WARNING
184
+ end
185
+ end
186
+ found.first
187
+ end
188
+
189
+ # Splits a filename into three parts, a directory part, a basename, and an extension
190
+ # Only the known extensions returned from the extensions method will be recognized as such.
191
+ def split(name)
192
+ extension = nil
193
+ dirname, basename = File.dirname(name), File.basename(name)
194
+ if basename =~ /^(.*)\.(#{extensions.keys.map{|e| Regexp.escape(e)}.join('|')})$/
195
+ basename = $1
196
+ extension = $2
197
+ end
198
+ [dirname, basename, extension]
199
+ end
200
+
201
+ private
202
+
203
+ def strip_varname(name)
204
+ name.include?(".json?") ? name[0..name.rindex("?")-1] : name
205
+ end
206
+
207
+
208
+ def _find(dir, name, options)
209
+ if name.include? ".json?"
210
+ quotePos = name.rindex("?");
211
+ path = name[0..quotePos-1]
212
+ varname = name[quotePos+1..-1]
213
+
214
+ full_filename, syntax = Sass::Util.destructure(find_real_file(dir, path, options))
215
+ return unless full_filename && File.readable?(full_filename)
216
+
217
+ options[:syntax] = syntax
218
+ options[:filename] = full_filename
219
+ options[:importer] = self
220
+
221
+ Sass::Engine.new("$#{varname} : json_decode('" + File.read(full_filename) + "');", options)
222
+ else
223
+ Sass::Engine.new("$hello:'test';", options)
224
+ end
225
+ end
226
+
227
+ end
228
+ end
229
+ end
data/lib/SassyJSON.rb CHANGED
@@ -5,8 +5,8 @@ Compass::Frameworks.register('SassyJSON', :path => extension_path)
5
5
  # Version is a number. If a version contains alphas, it will be created as a prerelease version
6
6
  # Date is in the form of YYYY-MM-DD
7
7
  module SassyJSON
8
- VERSION = "1.0.11"
9
- DATE = "2014-01-23"
8
+ VERSION = "1.1.0"
9
+ DATE = "2014-01-29"
10
10
  end
11
11
 
12
12
  module Sass::Script::Functions
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: SassyJSON
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.11
4
+ version: 1.1.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Hugo Giraudel
@@ -9,7 +10,7 @@ authors:
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2014-01-23 00:00:00.000000000 Z
13
+ date: 2014-01-29 00:00:00.000000000 Z
13
14
  dependencies: []
14
15
  description: Sass API for JSON
15
16
  email:
@@ -21,6 +22,7 @@ extra_rdoc_files: []
21
22
  files:
22
23
  - README.md
23
24
  - CHANGELOG.md
25
+ - lib/JsonImporter.rb
24
26
  - lib/SassyJSON.rb
25
27
  - stylesheets/decode/api/_json.scss
26
28
  - stylesheets/decode/decode.scss
@@ -60,26 +62,27 @@ files:
60
62
  - stylesheets/SassyJSON.scss
61
63
  homepage: https://github.com/HugoGiraudel/SassyJSON/
62
64
  licenses: []
63
- metadata: {}
64
65
  post_install_message:
65
66
  rdoc_options: []
66
67
  require_paths:
67
68
  - lib
68
69
  required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
69
71
  requirements:
70
- - - '>='
72
+ - - ! '>='
71
73
  - !ruby/object:Gem::Version
72
74
  version: '0'
73
75
  required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
74
77
  requirements:
75
- - - '>='
78
+ - - ! '>='
76
79
  - !ruby/object:Gem::Version
77
80
  version: 1.3.6
78
81
  requirements: []
79
82
  rubyforge_project: SassyJSON
80
- rubygems_version: 2.0.3
83
+ rubygems_version: 1.8.24
81
84
  signing_key:
82
- specification_version: 4
85
+ specification_version: 3
83
86
  summary: SassyJSON is a Sass-powered API for JSON. It provides you the classic json-encode
84
87
  and json-decode directly from your Sass files.
85
88
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: b252de6ac6970e21a3b2cdcdfecbc263064be64d
4
- data.tar.gz: 98888fa1e6ace45183f65b96809eb4945a211376
5
- SHA512:
6
- metadata.gz: ed3b1b5469126f55682340b2f0957ff2bcc13faa9c289a280e35c3a4c97c960627b50941378dd1dfa1c5e611719627be10151946b849e91762d94e54cad492b0
7
- data.tar.gz: c319e4e58baa7e2cd4316a227ac2809eb6a9ae67fb9e413ad537e65298b81d18b5c97c13358d2afa94216d02ce9274b9e10cedb709a6aedb87ba596c666e94b1