Permalink
Browse files

First import

  • Loading branch information...
0 parents commit c4f9cbdfb4339110377b0d6714157a6257f95c13 @fd committed May 23, 2011
Showing with 2,404 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +7 −0 Gemfile
  3. +20 −0 LICENSE
  4. +67 −0 README.md
  5. +18 −0 Rakefile
  6. +23 −0 json_select.gemspec
  7. +35 −0 lib/json_select.rb
  8. +14 −0 lib/json_select/ast/combination_selector.rb
  9. +27 −0 lib/json_select/ast/complex_expr.rb
  10. +7 −0 lib/json_select/ast/even_expr.rb
  11. +12 −0 lib/json_select/ast/hash_selector.rb
  12. +7 −0 lib/json_select/ast/odd_expr.rb
  13. +24 −0 lib/json_select/ast/pseudo_selector.rb
  14. +17 −0 lib/json_select/ast/selector_group.rb
  15. +7 −0 lib/json_select/ast/simple_expr.rb
  16. +23 −0 lib/json_select/ast/simple_selector.rb
  17. +8 −0 lib/json_select/ast/type_selector.rb
  18. +7 −0 lib/json_select/ast/universal_selector.rb
  19. +19 −0 lib/json_select/parser.rb
  20. +176 −0 lib/json_select/selector.rb
  21. +1,251 −0 lib/json_select/selector_parser.rb
  22. +161 −0 lib/json_select/selector_parser.tt
  23. +3 −0 lib/json_select/version.rb
  24. +41 −0 spec/conformance_spec.rb
  25. +14 −0 spec/fixtures/README.md
  26. +31 −0 spec/fixtures/alltests.txt
  27. +31 −0 spec/fixtures/basic.json
  28. +31 −0 spec/fixtures/basic.xml
  29. +6 −0 spec/fixtures/basic_first-child.ast
  30. +6 −0 spec/fixtures/basic_first-child.output
  31. +2 −0 spec/fixtures/basic_first-child.selector
  32. +12 −0 spec/fixtures/basic_grouping.ast
  33. +4 −0 spec/fixtures/basic_grouping.output
  34. +1 −0 spec/fixtures/basic_grouping.selector
  35. +3 −0 spec/fixtures/basic_id.ast
  36. +1 −0 spec/fixtures/basic_id.output
  37. +1 −0 spec/fixtures/basic_id.selector
  38. +3 −0 spec/fixtures/basic_id_multiple.ast
  39. +3 −0 spec/fixtures/basic_id_multiple.output
  40. +1 −0 spec/fixtures/basic_id_multiple.selector
  41. +3 −0 spec/fixtures/basic_id_quotes.ast
  42. +2 −0 spec/fixtures/basic_id_quotes.output
  43. +1 −0 spec/fixtures/basic_id_quotes.selector
  44. +4 −0 spec/fixtures/basic_id_with_type.ast
  45. +1 −0 spec/fixtures/basic_id_with_type.output
  46. +1 −0 spec/fixtures/basic_id_with_type.selector
  47. +6 −0 spec/fixtures/basic_last-child.ast
  48. +6 −0 spec/fixtures/basic_last-child.output
  49. +2 −0 spec/fixtures/basic_last-child.selector
  50. +6 −0 spec/fixtures/basic_nth-child-2.ast
  51. +13 −0 spec/fixtures/basic_nth-child-2.output
  52. +1 −0 spec/fixtures/basic_nth-child-2.selector
  53. +6 −0 spec/fixtures/basic_nth-child.ast
  54. +7 −0 spec/fixtures/basic_nth-child.output
  55. +1 −0 spec/fixtures/basic_nth-child.selector
  56. +6 −0 spec/fixtures/basic_nth-last-child.ast
  57. +6 −0 spec/fixtures/basic_nth-last-child.output
  58. +1 −0 spec/fixtures/basic_nth-last-child.selector
  59. +3 −0 spec/fixtures/basic_root_pseudo.ast
  60. +31 −0 spec/fixtures/basic_root_pseudo.output
  61. +1 −0 spec/fixtures/basic_root_pseudo.selector
  62. +3 −0 spec/fixtures/basic_type.ast
  63. +14 −0 spec/fixtures/basic_type.output
  64. +1 −0 spec/fixtures/basic_type.selector
  65. +3 −0 spec/fixtures/basic_type2.ast
  66. +1 −0 spec/fixtures/basic_type2.output
  67. +1 −0 spec/fixtures/basic_type2.selector
  68. +3 −0 spec/fixtures/basic_type3.ast
  69. +47 −0 spec/fixtures/basic_type3.output
  70. +1 −0 spec/fixtures/basic_type3.selector
  71. +2 −0 spec/fixtures/basic_universal.ast
  72. +85 −0 spec/fixtures/basic_universal.output
  73. +1 −0 spec/fixtures/basic_universal.selector
  74. +6 −0 spec/spec_helper.rb
@@ -0,0 +1,4 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
@@ -0,0 +1,7 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in json_select.gemspec
+gemspec
+
+gem 'rspec'
+gem 'yajl-ruby'
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Simon Menke
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,67 @@
+# JSONSelect
+
+**CSS-like selectors for JSON.**
+
+[More info about the JSON:select format](http://jsonselect.org/)
+
+## Installation
+
+From your terminal:
+
+```bash
+gem install json_select
+```
+
+In your `Gemfile`:
+
+```ruby
+gem 'json_select'
+```
+
+## Usage
+
+```ruby
+require 'json_select'
+
+json = { # This would normally be load with something like yajl-ruby
+ "name" => {
+ "first" => "Lloyd",
+ "last" => "Hilaiel"
+ },
+ "favoriteColor" => "yellow",
+ "languagesSpoken" => [
+ {
+ "language" => "Bulgarian",
+ "level" => "advanced"
+ },
+ {
+ "language" => "English",
+ "level" => "native"
+ },
+ {
+ "language" => "Spanish",
+ "level" => "beginner"
+ }
+ ],
+ "seatingPreference" => [ "window", "aisle" ],
+ "drinkPreference" => [ "beer", "whiskey", "wine" ],
+ "weight" => 172
+}
+
+JSONSelect('string:first-child') # => ["Lloyd", "Bulgarian", "English", "Spanish", "window", "beer"]
+```
+
+## Note on Patches/Pull Requests
+
+* Fork the project.
+* Make your feature addition or bug fix.
+* Add tests for it. This is important so I don't break it in a future version
+ unintentionally.
+* Commit, do not mess with `Rakefile` or version. (if you want to have your
+ own version, that is fine but bump version in a commit by itself I can
+ ignore when I pull)
+* Send me a pull request. Bonus points for topic branches.
+
+## Copyright
+
+Copyright (c) 2011 Simon Menke. See LICENSE for details.
@@ -0,0 +1,18 @@
+require 'bundler'
+Bundler::GemHelper.install_tasks
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new do |t|
+ t.pattern = "./spec/**/*_spec.rb"
+ t.rspec_opts = [
+ '--color',
+ '-r', File.expand_path("../spec/spec_helper.rb", __FILE__)]
+end
+
+task :build_parser do
+ sh "bundle exec tt lib/json_select/selector_parser.tt -o lib/json_select/selector_parser.rb"
+end
+
+task :spec => :build_parser
+task :build => :build_parser
+task :default => :spec
@@ -0,0 +1,23 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "json_select/version"
+
+Gem::Specification.new do |s|
+ s.name = "json_select"
+ s.version = JSONSelect::VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["Simon Menke"]
+ s.email = ["simon.menke@gmail.com"]
+ s.homepage = "http://github.com/fd/json_select"
+ s.summary = %q{JSONSelect implementation for Ruby}
+ s.description = %q{JSONSelect implementation for Ruby}
+
+ s.rubyforge_project = "json_select"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+
+ s.add_runtime_dependency 'treetop'
+end
@@ -0,0 +1,35 @@
+module JSONSelect
+
+ require 'treetop'
+
+ require 'json_select/version'
+ require 'json_select/selector_parser'
+ require 'json_select/selector'
+ require 'json_select/parser'
+
+ module Ast
+ require 'json_select/ast/combination_selector'
+ require 'json_select/ast/simple_selector'
+ require 'json_select/ast/selector_group'
+ require 'json_select/ast/type_selector'
+ require 'json_select/ast/hash_selector'
+ require 'json_select/ast/pseudo_selector'
+ require 'json_select/ast/universal_selector'
+
+ require 'json_select/ast/odd_expr'
+ require 'json_select/ast/even_expr'
+ require 'json_select/ast/simple_expr'
+ require 'json_select/ast/complex_expr'
+ end
+
+ ParseError = Class.new(RuntimeError)
+
+ def self.parse(selector)
+ JSONSelect::Parser.new(selector).parse
+ end
+
+end
+
+def JSONSelect(selector)
+ JSONSelect.parse(selector)
+end
@@ -0,0 +1,14 @@
+module JSONSelect::Ast::CombinationSelector
+
+ def to_ast
+ ast = [a.to_ast]
+
+ b.elements.each do |comb|
+ ast.push('>') if comb.c.text_value.strip == '>'
+ ast.push(comb.d.to_ast)
+ end
+
+ ast
+ end
+
+end
@@ -0,0 +1,27 @@
+module JSONSelect::Ast::ComplexExpr
+
+ def to_ast
+ _a = ""
+
+ if a.text_value.size > 0
+ _a += a.text_value
+ else
+ _a += '+'
+ end
+
+ if b.text_value.size > 0
+ _a += b.text_value
+ else
+ _a += '1'
+ end
+
+ if c.text_value.size > 0
+ _b = c.text_value.to_i
+ else
+ _b = 0
+ end
+
+ { 'a' => _a.to_i, 'b' => _b }
+ end
+
+end
@@ -0,0 +1,7 @@
+module JSONSelect::Ast::EvenExpr
+
+ def to_ast
+ { 'a' => 2, 'b' => 0 }
+ end
+
+end
@@ -0,0 +1,12 @@
+module JSONSelect::Ast::HashSelector
+
+ def to_ast
+ tv = self.text_value[1..-1]
+ if tv[0,1] == '"'
+ { "class" => eval(tv) }
+ else
+ { "class" => tv }
+ end
+ end
+
+end
@@ -0,0 +1,7 @@
+module JSONSelect::Ast::OddExpr
+
+ def to_ast
+ { 'a' => 2, 'b' => 1 }
+ end
+
+end
@@ -0,0 +1,24 @@
+module JSONSelect::Ast::PseudoSelector
+
+ def to_ast
+ if respond_to?(:e)
+ ast = { "pseudo_function" => a.text_value, 'a' => 0 , 'b' => 0 }
+ ast.merge!(e.to_ast)
+ ast
+ else
+ case a.text_value
+
+ when 'first-child'
+ { "pseudo_function" => 'nth-child', 'a' => 0, 'b' => 1 }
+
+ when 'last-child'
+ { "pseudo_function" => 'nth-last-child', 'a' => 0, 'b' => 1 }
+
+ else
+ { "pseudo_class" => a.text_value }
+
+ end
+ end
+ end
+
+end
@@ -0,0 +1,17 @@
+module JSONSelect::Ast::SelectorGroup
+
+ def to_ast
+ if b.elements.empty?
+ return a.to_ast
+ end
+
+ ast = [',', a.to_ast]
+
+ b.elements.each do |group|
+ ast.push group.c.to_ast
+ end
+
+ ast
+ end
+
+end
@@ -0,0 +1,7 @@
+module JSONSelect::Ast::SimpleExpr
+
+ def to_ast
+ { 'a' => 0, 'b' => text_value.to_i }
+ end
+
+end
@@ -0,0 +1,23 @@
+module JSONSelect::Ast::SimpleSelector
+
+ def to_ast
+ ast = {}
+
+ if respond_to?(:a) and respond_to?(:b)
+ ast.merge! a.to_ast
+
+ b.elements.each do |s|
+ ast.merge!(s.to_ast)
+ end
+
+ else
+ self.elements.each do |s|
+ ast.merge!(s.to_ast)
+ end
+
+ end
+
+ ast
+ end
+
+end
@@ -0,0 +1,8 @@
+module JSONSelect::Ast::TypeSelector
+
+ # `object` | `array` | `number` | `string` | `boolean` | `null`
+ def to_ast
+ { "type" => self.text_value }
+ end
+
+end
@@ -0,0 +1,7 @@
+module JSONSelect::Ast::UniversalSelector
+
+ def to_ast
+ {}
+ end
+
+end
@@ -0,0 +1,19 @@
+class JSONSelect::Parser
+
+ def initialize(source)
+ @parser = JSONSelect::SelectorParserParser.new
+ @source = source
+ end
+
+ def parse
+ tree = @parser.parse(@source)
+ if tree
+ JSONSelect::Selector.new(tree.to_ast)
+ else
+ raise JSONSelect::ParseError, @parser.failure_reason
+ # puts parser.failure_line
+ # puts parser.failure_column
+ end
+ end
+
+end
Oops, something went wrong.

0 comments on commit c4f9cbd

Please sign in to comment.