dotum 0.0.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.
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