dotum 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.groc.json +6 -0
  4. data/.rspec +4 -0
  5. data/.simplecov +5 -0
  6. data/.travis.yml +15 -0
  7. data/CONTRIBUTING.md +63 -0
  8. data/Gemfile +59 -0
  9. data/Guardfile +30 -0
  10. data/MIT-LICENSE.md +21 -0
  11. data/README.md +24 -0
  12. data/Rakefile +15 -0
  13. data/bin/dotum +7 -0
  14. data/data/default_rules.dotum +44 -0
  15. data/dotum.gemspec +19 -0
  16. data/extern/json/CHANGES.md +9 -0
  17. data/extern/json/COPYING +58 -0
  18. data/extern/json/README.rdoc +358 -0
  19. data/extern/json/lib/json.rb +62 -0
  20. data/extern/json/lib/json/.DS_Store +0 -0
  21. data/extern/json/lib/json/add/bigdecimal.rb +28 -0
  22. data/extern/json/lib/json/add/complex.rb +22 -0
  23. data/extern/json/lib/json/add/core.rb +11 -0
  24. data/extern/json/lib/json/add/date.rb +34 -0
  25. data/extern/json/lib/json/add/date_time.rb +50 -0
  26. data/extern/json/lib/json/add/exception.rb +31 -0
  27. data/extern/json/lib/json/add/ostruct.rb +31 -0
  28. data/extern/json/lib/json/add/range.rb +29 -0
  29. data/extern/json/lib/json/add/rational.rb +22 -0
  30. data/extern/json/lib/json/add/regexp.rb +30 -0
  31. data/extern/json/lib/json/add/struct.rb +30 -0
  32. data/extern/json/lib/json/add/symbol.rb +25 -0
  33. data/extern/json/lib/json/add/time.rb +38 -0
  34. data/extern/json/lib/json/common.rb +487 -0
  35. data/extern/json/lib/json/generic_object.rb +70 -0
  36. data/extern/json/lib/json/pure.rb +21 -0
  37. data/extern/json/lib/json/pure/generator.rb +522 -0
  38. data/extern/json/lib/json/pure/parser.rb +359 -0
  39. data/extern/json/lib/json/version.rb +8 -0
  40. data/lib/dotum.rb +11 -0
  41. data/lib/dotum/abstract_rules.rb +5 -0
  42. data/lib/dotum/abstract_rules/base.rb +56 -0
  43. data/lib/dotum/abstract_rules/globbable_files.rb +51 -0
  44. data/lib/dotum/abstract_rules/options_base.rb +33 -0
  45. data/lib/dotum/autoload_convention.rb +34 -0
  46. data/lib/dotum/cli.rb +35 -0
  47. data/lib/dotum/context.rb +55 -0
  48. data/lib/dotum/externs/json.rb +9 -0
  49. data/lib/dotum/logger.rb +50 -0
  50. data/lib/dotum/options_context.rb +21 -0
  51. data/lib/dotum/rule_dsl.rb +73 -0
  52. data/lib/dotum/rule_options_dsl.rb +116 -0
  53. data/lib/dotum/rule_runner.rb +16 -0
  54. data/lib/dotum/rules.rb +5 -0
  55. data/lib/dotum/rules/cd.rb +23 -0
  56. data/lib/dotum/rules/download.rb +32 -0
  57. data/lib/dotum/rules/link.rb +22 -0
  58. data/lib/dotum/rules/repo.rb +65 -0
  59. data/lib/dotum/rules/require_extension.rb +42 -0
  60. data/lib/dotum/rules/run.rb +23 -0
  61. data/lib/dotum/rules/use.rb +33 -0
  62. data/lib/dotum/rules/use_repo.rb +58 -0
  63. data/lib/dotum/standard_options.rb +5 -0
  64. data/lib/dotum/standard_options/destination.rb +22 -0
  65. data/lib/dotum/util.rb +5 -0
  66. data/lib/dotum/util/ansi_colors.rb +26 -0
  67. data/lib/dotum/util/path.rb +120 -0
  68. data/lib/dotum/version.rb +5 -0
  69. data/spec/fixtures/autoload_convention/abc_one_two_three.rb +7 -0
  70. data/spec/fixtures/autoload_convention/allcaps.rb +7 -0
  71. data/spec/fixtures/autoload_convention/mismatched.rb +3 -0
  72. data/spec/fixtures/autoload_convention/multi_token.rb +7 -0
  73. data/spec/fixtures/autoload_convention/single.rb +7 -0
  74. data/spec/fixtures/autoload_convention/string.rb +7 -0
  75. data/spec/spec_helper.rb +76 -0
  76. data/spec/unit/dotum/autoload_convention/const_missing_spec.rb +57 -0
  77. data/tasks/console.rake +9 -0
  78. data/tasks/spec.rake +7 -0
  79. data/tasks/spec/ci.rake +16 -0
  80. data/tasks/spec/coverage.rake +19 -0
  81. data/tasks/spec/mutate.rake +71 -0
  82. metadata +123 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 58b55404177eb830e45206bf1ea8f436832f8101
4
+ data.tar.gz: 64901256ed0f3cd0ba95c6778d366a9f77502f40
5
+ SHA512:
6
+ metadata.gz: 77e1a6e498214d1894a1b0c4bebd85e38a5fd4fe90a1dc44d7926871f3524c1a15778bd42e1f03ee16d175d582db513768357cc73631180b86b2008e447bcbe2
7
+ data.tar.gz: 7da1852a32c139a9921b8189d6cd61743bb65861e0a6faa927f7cba31cffd44a720797b838f64895b7f0f72354f52a97193b8b611cec61deff811e4a6e56b917
@@ -0,0 +1,5 @@
1
+ coverage/
2
+ doc/
3
+ pkg/
4
+ tmp/
5
+ Gemfile.lock
@@ -0,0 +1,6 @@
1
+ {
2
+ "glob": ["lib/**/*.rb", "README.md"],
3
+ "strip": ["lib/", "lib/dotum/"],
4
+ "github": true,
5
+ "whitespace-after-token": false
6
+ }
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format documentation
3
+ --order random
4
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ SimpleCov.start do
4
+ add_filter "/spec/"
5
+ end
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ bundler_args: --without debugging guard
3
+ script: bundle exec rake spec:ci
4
+ rvm:
5
+ - 1.8.7
6
+ - 1.9.2
7
+ - 1.9.3
8
+ - 2.0.0
9
+ - rbx-18mode
10
+ - rbx-19mode
11
+ - rbx-20mode
12
+ - jruby-18mode
13
+ - jruby-19mode
14
+ - jruby-20mode
15
+ - ree
@@ -0,0 +1,63 @@
1
+ Hacking on Dotum
2
+ =================
3
+
4
+ Hopefully, Dotum's development environment is relatively straightfoward, but
5
+ here's a walkthrough of its different facets.
6
+
7
+
8
+ General Workflow
9
+ ----------------
10
+
11
+ After checking out Dotum and installing its bundle, you should simply run
12
+ `bundle exec guard` in a separate terminal window (or process).
13
+
14
+ The general philosophy is that [Guard](https://github.com/guard/guard) should be
15
+ managing the majority of the development workflow. Any change you make should
16
+ run the appropriate tests.
17
+
18
+
19
+ Mutation-Driven Testing
20
+ -----------------------
21
+
22
+ Dotum strictly adheres to [mutation tests](tasks/spec/mutate.rake) for all core
23
+ classes (not rules) via [mutant](https://github.com/mbj/mutant). This may be a
24
+ bit more stringent than you are used to, but it provides the following benefits:
25
+
26
+ * **Complete coverage.** Mutant will mutate just about every facet of every
27
+ function.
28
+
29
+ * **Confidence.** If the specs pass mutation testing, you can be reasonably
30
+ assured that a pull requests behaves as advertised.
31
+
32
+ * **Redundancy avoidance.** Mutation tests tend to highlight redundant and
33
+ useless code that can be safely removed.
34
+
35
+ * **Enforced granularity.** You tend to write smaller and more focused tests.
36
+
37
+ Mutation tests do not run via `guard` (they take a while). You should
38
+ periodically run them via `rake` or `rake spec:mutate`. You can also emulate
39
+ the Travis environment via `rake spec:ci`.
40
+
41
+ Additionally, you can run mutation specs against specific objects and/or methods
42
+ by specifying them directly:
43
+
44
+ * `rake spec:mutate[Foo]` would run mutation specs for methods defined on
45
+ `Dotum::Foo`.
46
+
47
+ * `rake spec:mutate[Foo#bar]` would run mutation specs for the instance method
48
+ `bar` defined on `Dotum::Foo`.
49
+
50
+ * `rake spec:mutate[Fizz.buzz]` would run mutation specs for the module method
51
+ `buzz` defined on `Dotum::Fizz`.
52
+
53
+
54
+ Test Organization
55
+ -----------------
56
+
57
+ Both to support mutant, and for better visibility, tests are organized
58
+ _per-method_. For example:
59
+
60
+ * `Foo::Bar#baz` should have tests located at `spec/unit/foo/bar/baz_spec.rb`.
61
+
62
+ * `Fizz.buzz` should have tests located at
63
+ `spec/unit/class_methods/buzz_spec.rb`.
data/Gemfile ADDED
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ # No gem would be complete without rake tasks - http://rake.rubyforge.org/
8
+ gem "rake", "~> 10.1"
9
+
10
+ group :test do
11
+ # Our preferred unit testing library - https://www.relishapp.com/rspec
12
+ gem "rspec", "~> 2.13"
13
+
14
+ # The preferred code mutation library.
15
+ gem "mutant", "~> 0.3.rc", :platforms => [:ruby_19, :ruby_20]
16
+
17
+ # Cover all the things - https://github.com/colszowka/simplecov
18
+ gem "simplecov", "~> 0.7"
19
+
20
+ # Code coverage in badge form - https://coveralls.io/
21
+ gem "coveralls", "~> 0.6"
22
+ end
23
+
24
+ group :debugging do
25
+ # A REPL like IRB, but much better - http://pryrepl.org/
26
+ gem "pry", "~> 0.9"
27
+
28
+ # Don't leave home without a debugger!
29
+ gem "debugger", "~> 1.6", :platforms => :mri
30
+ end
31
+
32
+ group :guard do
33
+ # A generic file system event handler; spin it up and see the tests fly
34
+ gem "guard", "~> 1.8"
35
+
36
+ # Guard configuration to manage our spork drb environments
37
+ gem "guard-spork", "~> 1.5"
38
+
39
+ # Guard configuration & hooks for rspec
40
+ gem "guard-rspec", "~> 3.0"
41
+
42
+ # File system event hooks for OS X
43
+ gem "rb-fsevent", "~> 0.9"
44
+
45
+ # File system event hooks for Linux
46
+ gem "rb-inotify", "~> 0.9"
47
+
48
+ # File system event hooks for Windows
49
+ gem "rb-fchange", "~> 0.0"
50
+
51
+ # OS X 10.8+ notification center support
52
+ gem "terminal-notifier-guard", "~> 1.5"
53
+
54
+ # libnotify bindings (Linux)
55
+ gem "libnotify", "~> 0.8"
56
+
57
+ # notifu adapter (Windows)
58
+ gem "rb-notifu", "~> 0.0"
59
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ guard "spork", rspec_port: 2772 do
4
+ watch("Gemfile")
5
+ watch("Gemfile.lock")
6
+
7
+ # Touching any of these files should cause the entire test suite to reload.
8
+ SPEC_ENVIRONMENT_FILES = [
9
+ ".rspec",
10
+ %r{^spec/.*_helper\.rb$},
11
+ %r{^spec/common/.*\.rb$},
12
+ ]
13
+
14
+ SPEC_ENVIRONMENT_FILES.each do |pattern|
15
+ watch(pattern) { :rspec }
16
+ end
17
+ end
18
+
19
+ def specs_for_path(path)
20
+ ["spec/unit/#{path}_spec.rb", Dir["spec/unit/#{path}/**/*_spec.rb"]].flatten
21
+ end
22
+
23
+ guard "rspec", cli: "--drb --drb-port 2772" do
24
+ watch("lib/dotum.rb") { "spec" }
25
+ watch("lib/dotum/autoload_convention.rb") { "spec" }
26
+ watch(%r{^spec/fixtures/.*\.rb$}) { "spec" }
27
+
28
+ watch(%r{^spec/.+_spec\.rb$})
29
+ watch(%r{^lib/(.+)\.rb$}) { |m| specs_for_path(m[1]) }
30
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+ =====================
3
+ Copyright (c) 2013 Ian MacLeod <ian@nevir.net>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,24 @@
1
+ Dotum
2
+ =====
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/dotum.png)](https://rubygems.org/gems/dotum)
5
+ [![Build Status](https://secure.travis-ci.org/nevir/dotum.png?branch=master)](http://travis-ci.org/nevir/dotum)
6
+ [![Coverage Status](https://coveralls.io/repos/nevir/dotum/badge.png?branch=master)](https://coveralls.io/r/nevir/dotum)
7
+ [![Code Climate](https://codeclimate.com/github/nevir/dotum.png)](https://codeclimate.com/github/nevir/dotum)
8
+
9
+ Dotum manages your dotfiles and allows for piecemeal sharing.
10
+
11
+ TODO.
12
+
13
+
14
+ License
15
+ -------
16
+
17
+ Dotum is MIT licensed. [See the accompanying file](MIT-LICENSE.md) for the
18
+ full text.
19
+
20
+ Dotum [also includes](extern/json/CHANGES.md) the pure-Ruby portions of
21
+ [flori's JSON implementation](https://github.com/flori/json), which is
22
+ [Ruby licensed](extern/json/COPYING). This is used for Ruby implementations
23
+ that do not already bundle it (i.e. 1.8), so that Dotum doesn't have to depend
24
+ on other gems.
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env rake
2
+ # encoding: utf-8
3
+
4
+ require "bundler/gem_tasks"
5
+
6
+ PROJECT_ROOT = File.expand_path("..", __FILE__)
7
+ Dir["#{PROJECT_ROOT}/tasks/**/*.rake"].each do |path|
8
+ load path
9
+ end
10
+
11
+ $LOAD_PATH.unshift File.join(PROJECT_ROOT, "lib")
12
+
13
+
14
+ desc "Run the full test suite"
15
+ task :default => [:spec, :"spec:mutate"]
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
5
+ require "dotum"
6
+
7
+ Dotum::CLI.exec(ARGV)
@@ -0,0 +1,44 @@
1
+ # Default `use` Behavior
2
+ # ======================
3
+
4
+
5
+ # Package Loading
6
+ # --------------
7
+ # Any directories that contain a `rules.dotum` are `use`d.
8
+ package_paths = package_dir.relative_glob("**/rules.dotum")
9
+ package_paths.map! { |p| File.dirname(p) }
10
+
11
+ if package_paths.size > 1
12
+ package_paths.sort!
13
+
14
+ # but only the outermost packages.
15
+ #
16
+ # Parent packages get to dictate how their children are loaded.
17
+ filtered_paths = []
18
+ prev_path = nil
19
+ package_paths.each_with_index do |path, i|
20
+ next if prev_path && path.start_with?(prev_path)
21
+
22
+ prev_path = path
23
+ filtered_paths.push(path)
24
+ end
25
+
26
+ package_paths = filtered_paths
27
+ end
28
+
29
+ package_paths.each do |package_path|
30
+ use package_path
31
+ end
32
+
33
+
34
+ # Linking
35
+ # -------
36
+ # We link everything that doesn't fall under a package path.
37
+ file_paths = package_dir.relative_glob("**/*", &:file?)
38
+ file_paths.reject! { |file_path|
39
+ package_paths.any? { |package_path| file_path.start_with? package_path }
40
+ }
41
+
42
+ file_paths.each do |file_path|
43
+ link file_path
44
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path("../lib/dotum/version", __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "dotum"
7
+ gem.summary = "Dotum manages your dotfiles and allows for piecemeal sharing."
8
+ gem.authors = ["Ian MacLeod"]
9
+ gem.email = ["ian@nevir.net"]
10
+ gem.homepage = "https://github.com/nevir/dotum"
11
+
12
+ gem.version = Dotum::VERSION
13
+ gem.platform = Gem::Platform::RUBY
14
+
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- {spec}/*`.split("\n")
17
+
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,9 @@
1
+ Changes for Dotum
2
+ =================
3
+
4
+ This JSON library was found at https://github.com/flori/json.
5
+
6
+ There are _no_ code changes, but it has been stripped down to just the pure Ruby
7
+ implementation.
8
+
9
+ Dotum only uses this if a native JSON library is not available (aka 1.8).
@@ -0,0 +1,58 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.co.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the GPL
3
+ (see GPL file), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) rename any non-standard executables so the names do not conflict
21
+ with standard executables, which must also be provided.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or executable
26
+ form, provided that you do at least ONE of the following:
27
+
28
+ a) distribute the executables and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard executables non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under this terms.
43
+
44
+ They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
45
+ files under the ./missing directory. See each file for the copying
46
+ condition.
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
58
+
@@ -0,0 +1,358 @@
1
+ = JSON implementation for Ruby {<img src="https://secure.travis-ci.org/flori/json.png" />}[http://travis-ci.org/flori/json]
2
+
3
+ == Description
4
+
5
+ This is a implementation of the JSON specification according to RFC 4627
6
+ http://www.ietf.org/rfc/rfc4627.txt . Starting from version 1.0.0 on there
7
+ will be two variants available:
8
+
9
+ * A pure ruby variant, that relies on the iconv and the stringscan
10
+ extensions, which are both part of the ruby standard library.
11
+ * The quite a bit faster C extension variant, which is in parts implemented
12
+ in C and comes with its own unicode conversion functions and a parser
13
+ generated by the ragel state machine compiler
14
+ http://www.cs.queensu.ca/~thurston/ragel .
15
+
16
+ Both variants of the JSON generator generate UTF-8 character sequences by
17
+ default. If an :ascii_only option with a true value is given, they escape all
18
+ non-ASCII and control characters with \uXXXX escape sequences, and support
19
+ UTF-16 surrogate pairs in order to be able to generate the whole range of
20
+ unicode code points.
21
+
22
+ All strings, that are to be encoded as JSON strings, should be UTF-8 byte
23
+ sequences on the Ruby side. To encode raw binary strings, that aren't UTF-8
24
+ encoded, please use the to_json_raw_object method of String (which produces
25
+ an object, that contains a byte array) and decode the result on the receiving
26
+ endpoint.
27
+
28
+ The JSON parsers can parse UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, and UTF-32LE
29
+ JSON documents under Ruby 1.8. Under Ruby 1.9 they take advantage of Ruby's
30
+ M17n features and can parse all documents which have the correct
31
+ String#encoding set. If a document string has ASCII-8BIT as an encoding the
32
+ parser attempts to figure out which of the UTF encodings from above it is and
33
+ trys to parse it.
34
+
35
+ == Installation
36
+
37
+ It's recommended to use the extension variant of JSON, because it's faster than
38
+ the pure ruby variant. If you cannot build it on your system, you can settle
39
+ for the latter.
40
+
41
+ Just type into the command line as root:
42
+
43
+ # rake install
44
+
45
+ The above command will build the extensions and install them on your system.
46
+
47
+ # rake install_pure
48
+
49
+ or
50
+
51
+ # ruby install.rb
52
+
53
+ will just install the pure ruby implementation of JSON.
54
+
55
+ If you use Rubygems you can type
56
+
57
+ # gem install json
58
+
59
+ instead, to install the newest JSON version.
60
+
61
+ There is also a pure ruby json only variant of the gem, that can be installed
62
+ with:
63
+
64
+ # gem install json_pure
65
+
66
+ == Compiling the extensions yourself
67
+
68
+ If you want to build the extensions yourself you need rake:
69
+
70
+ You can get it from rubyforge:
71
+ http://rubyforge.org/projects/rake
72
+
73
+ or just type
74
+
75
+ # gem install rake
76
+
77
+ for the installation via rubygems.
78
+
79
+ If you want to create the parser.c file from its parser.rl file or draw nice
80
+ graphviz images of the state machines, you need ragel from: http://www.cs.queensu.ca/~thurston/ragel
81
+
82
+
83
+ == Usage
84
+
85
+ To use JSON you can
86
+ require 'json'
87
+ to load the installed variant (either the extension 'json' or the pure
88
+ variant 'json_pure'). If you have installed the extension variant, you can
89
+ pick either the extension variant or the pure variant by typing
90
+ require 'json/ext'
91
+ or
92
+ require 'json/pure'
93
+
94
+ Now you can parse a JSON document into a ruby data structure by calling
95
+
96
+ JSON.parse(document)
97
+
98
+ If you want to generate a JSON document from a ruby data structure call
99
+ JSON.generate(data)
100
+
101
+ You can also use the pretty_generate method (which formats the output more
102
+ verbosely and nicely) or fast_generate (which doesn't do any of the security
103
+ checks generate performs, e. g. nesting deepness checks).
104
+
105
+ To create a valid JSON document you have to make sure, that the output is
106
+ embedded in either a JSON array [] or a JSON object {}. The easiest way to do
107
+ this, is by putting your values in a Ruby Array or Hash instance.
108
+
109
+ There are also the JSON and JSON[] methods which use parse on a String or
110
+ generate a JSON document from an array or hash:
111
+
112
+ document = JSON 'test' => 23 # => "{\"test\":23}"
113
+ document = JSON['test'] => 23 # => "{\"test\":23}"
114
+
115
+ and
116
+
117
+ data = JSON '{"test":23}' # => {"test"=>23}
118
+ data = JSON['{"test":23}'] # => {"test"=>23}
119
+
120
+ You can choose to load a set of common additions to ruby core's objects if
121
+ you
122
+ require 'json/add/core'
123
+
124
+ After requiring this you can, e. g., serialise/deserialise Ruby ranges:
125
+
126
+ JSON JSON(1..10) # => 1..10
127
+
128
+ To find out how to add JSON support to other or your own classes, read the
129
+ section "More Examples" below.
130
+
131
+ To get the best compatibility to rails' JSON implementation, you can
132
+ require 'json/add/rails'
133
+
134
+ Both of the additions attempt to require 'json' (like above) first, if it has
135
+ not been required yet.
136
+
137
+ == More Examples
138
+
139
+ To create a JSON document from a ruby data structure, you can call
140
+ JSON.generate like that:
141
+
142
+ json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
143
+ # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
144
+
145
+ To get back a ruby data structure from a JSON document, you have to call
146
+ JSON.parse on it:
147
+
148
+ JSON.parse json
149
+ # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
150
+
151
+ Note, that the range from the original data structure is a simple
152
+ string now. The reason for this is, that JSON doesn't support ranges
153
+ or arbitrary classes. In this case the json library falls back to call
154
+ Object#to_json, which is the same as #to_s.to_json.
155
+
156
+ It's possible to add JSON support serialization to arbitrary classes by
157
+ simply implementing a more specialized version of the #to_json method, that
158
+ should return a JSON object (a hash converted to JSON with #to_json) like
159
+ this (don't forget the *a for all the arguments):
160
+
161
+ class Range
162
+ def to_json(*a)
163
+ {
164
+ 'json_class' => self.class.name, # = 'Range'
165
+ 'data' => [ first, last, exclude_end? ]
166
+ }.to_json(*a)
167
+ end
168
+ end
169
+
170
+ The hash key 'json_class' is the class, that will be asked to deserialise the
171
+ JSON representation later. In this case it's 'Range', but any namespace of
172
+ the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
173
+ used to store the necessary data to configure the object to be deserialised.
174
+
175
+ If a the key 'json_class' is found in a JSON object, the JSON parser checks
176
+ if the given class responds to the json_create class method. If so, it is
177
+ called with the JSON object converted to a Ruby hash. So a range can
178
+ be deserialised by implementing Range.json_create like this:
179
+
180
+ class Range
181
+ def self.json_create(o)
182
+ new(*o['data'])
183
+ end
184
+ end
185
+
186
+ Now it possible to serialise/deserialise ranges as well:
187
+
188
+ json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
189
+ # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
190
+ JSON.parse json
191
+ # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
192
+
193
+ JSON.generate always creates the shortest possible string representation of a
194
+ ruby data structure in one line. This is good for data storage or network
195
+ protocols, but not so good for humans to read. Fortunately there's also
196
+ JSON.pretty_generate (or JSON.pretty_generate) that creates a more readable
197
+ output:
198
+
199
+ puts JSON.pretty_generate([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
200
+ [
201
+ 1,
202
+ 2,
203
+ {
204
+ "a": 3.141
205
+ },
206
+ false,
207
+ true,
208
+ null,
209
+ {
210
+ "json_class": "Range",
211
+ "data": [
212
+ 4,
213
+ 10,
214
+ false
215
+ ]
216
+ }
217
+ ]
218
+
219
+ There are also the methods Kernel#j for generate, and Kernel#jj for
220
+ pretty_generate output to the console, that work analogous to Core Ruby's p and
221
+ the pp library's pp methods.
222
+
223
+ The script tools/server.rb contains a small example if you want to test, how
224
+ receiving a JSON object from a webrick server in your browser with the
225
+ javasript prototype library http://www.prototypejs.org works.
226
+
227
+ == Speed Comparisons
228
+
229
+ I have created some benchmark results (see the benchmarks/data-p4-3Ghz
230
+ subdir of the package) for the JSON-parser to estimate the speed up in the C
231
+ extension:
232
+
233
+ Comparing times (call_time_mean):
234
+ 1 ParserBenchmarkExt#parser 900 repeats:
235
+ 553.922304770 ( real) -> 21.500x
236
+ 0.001805307
237
+ 2 ParserBenchmarkYAML#parser 1000 repeats:
238
+ 224.513358139 ( real) -> 8.714x
239
+ 0.004454078
240
+ 3 ParserBenchmarkPure#parser 1000 repeats:
241
+ 26.755020642 ( real) -> 1.038x
242
+ 0.037376163
243
+ 4 ParserBenchmarkRails#parser 1000 repeats:
244
+ 25.763381731 ( real) -> 1.000x
245
+ 0.038814780
246
+ calls/sec ( time) -> speed covers
247
+ secs/call
248
+
249
+ In the table above 1 is JSON::Ext::Parser, 2 is YAML.load with YAML
250
+ compatbile JSON document, 3 is is JSON::Pure::Parser, and 4 is
251
+ ActiveSupport::JSON.decode. The ActiveSupport JSON-decoder converts the
252
+ input first to YAML and then uses the YAML-parser, the conversion seems to
253
+ slow it down so much that it is only as fast as the JSON::Pure::Parser!
254
+
255
+ If you look at the benchmark data you can see that this is mostly caused by
256
+ the frequent high outliers - the median of the Rails-parser runs is still
257
+ overall smaller than the median of the JSON::Pure::Parser runs:
258
+
259
+ Comparing times (call_time_median):
260
+ 1 ParserBenchmarkExt#parser 900 repeats:
261
+ 800.592479481 ( real) -> 26.936x
262
+ 0.001249075
263
+ 2 ParserBenchmarkYAML#parser 1000 repeats:
264
+ 271.002390644 ( real) -> 9.118x
265
+ 0.003690004
266
+ 3 ParserBenchmarkRails#parser 1000 repeats:
267
+ 30.227910865 ( real) -> 1.017x
268
+ 0.033082008
269
+ 4 ParserBenchmarkPure#parser 1000 repeats:
270
+ 29.722384421 ( real) -> 1.000x
271
+ 0.033644676
272
+ calls/sec ( time) -> speed covers
273
+ secs/call
274
+
275
+ I have benchmarked the JSON-Generator as well. This generated a few more
276
+ values, because there are different modes that also influence the achieved
277
+ speed:
278
+
279
+ Comparing times (call_time_mean):
280
+ 1 GeneratorBenchmarkExt#generator_fast 1000 repeats:
281
+ 547.354332608 ( real) -> 15.090x
282
+ 0.001826970
283
+ 2 GeneratorBenchmarkExt#generator_safe 1000 repeats:
284
+ 443.968212317 ( real) -> 12.240x
285
+ 0.002252414
286
+ 3 GeneratorBenchmarkExt#generator_pretty 900 repeats:
287
+ 375.104545883 ( real) -> 10.341x
288
+ 0.002665923
289
+ 4 GeneratorBenchmarkPure#generator_fast 1000 repeats:
290
+ 49.978706968 ( real) -> 1.378x
291
+ 0.020008521
292
+ 5 GeneratorBenchmarkRails#generator 1000 repeats:
293
+ 38.531868759 ( real) -> 1.062x
294
+ 0.025952543
295
+ 6 GeneratorBenchmarkPure#generator_safe 1000 repeats:
296
+ 36.927649925 ( real) -> 1.018x 7 (>=3859)
297
+ 0.027079979
298
+ 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats:
299
+ 36.272134441 ( real) -> 1.000x 6 (>=3859)
300
+ 0.027569373
301
+ calls/sec ( time) -> speed covers
302
+ secs/call
303
+
304
+ In the table above 1-3 are JSON::Ext::Generator methods. 4, 6, and 7 are
305
+ JSON::Pure::Generator methods and 5 is the Rails JSON generator. It is now a
306
+ bit faster than the generator_safe and generator_pretty methods of the pure
307
+ variant but slower than the others.
308
+
309
+ To achieve the fastest JSON document output, you can use the fast_generate
310
+ method. Beware, that this will disable the checking for circular Ruby data
311
+ structures, which may cause JSON to go into an infinite loop.
312
+
313
+ Here are the median comparisons for completeness' sake:
314
+
315
+ Comparing times (call_time_median):
316
+ 1 GeneratorBenchmarkExt#generator_fast 1000 repeats:
317
+ 708.258020939 ( real) -> 16.547x
318
+ 0.001411915
319
+ 2 GeneratorBenchmarkExt#generator_safe 1000 repeats:
320
+ 569.105020353 ( real) -> 13.296x
321
+ 0.001757145
322
+ 3 GeneratorBenchmarkExt#generator_pretty 900 repeats:
323
+ 482.825371244 ( real) -> 11.280x
324
+ 0.002071142
325
+ 4 GeneratorBenchmarkPure#generator_fast 1000 repeats:
326
+ 62.717626652 ( real) -> 1.465x
327
+ 0.015944481
328
+ 5 GeneratorBenchmarkRails#generator 1000 repeats:
329
+ 43.965681162 ( real) -> 1.027x
330
+ 0.022745013
331
+ 6 GeneratorBenchmarkPure#generator_safe 1000 repeats:
332
+ 43.929073409 ( real) -> 1.026x 7 (>=3859)
333
+ 0.022763968
334
+ 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats:
335
+ 42.802514491 ( real) -> 1.000x 6 (>=3859)
336
+ 0.023363113
337
+ calls/sec ( time) -> speed covers
338
+ secs/call
339
+
340
+ == Author
341
+
342
+ Florian Frank <mailto:flori@ping.de>
343
+
344
+ == License
345
+
346
+ Ruby License, see the COPYING file included in the source distribution. The
347
+ Ruby License includes the GNU General Public License (GPL), Version 2, so see
348
+ the file GPL as well.
349
+
350
+ == Download
351
+
352
+ The latest version of this library can be downloaded at
353
+
354
+ * http://rubyforge.org/frs?group_id=953
355
+
356
+ Online Documentation should be located at
357
+
358
+ * http://json.rubyforge.org