SassyJSON 1.0.11 → 1.1.0

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