Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
benlangfeld committed Jun 9, 2011
0 parents commit 573499d
Show file tree
Hide file tree
Showing 12 changed files with 527 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
*.gem
.bundle
Gemfile.lock
pkg/*
4 changes: 4 additions & 0 deletions Gemfile
@@ -0,0 +1,4 @@
source "http://rubygems.org"

# Specify your gem's dependencies in niceogiri.gemspec
gemspec
22 changes: 22 additions & 0 deletions LICENSE
@@ -0,0 +1,22 @@
Niceogiri

Copyright (c) 2011 Jeff Smick, Ben Langfeld

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.
Empty file added README.md
Empty file.
27 changes: 27 additions & 0 deletions Rakefile
@@ -0,0 +1,27 @@
require 'rubygems'
require 'rake'

require 'bundler/gem_tasks'

require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.libs << 'lib' << 'spec'
test.pattern = 'spec/**/*_spec.rb'
test.verbose = true
end

require 'rcov/rcovtask'
Rcov::RcovTask.new do |test|
test.libs << 'spec'
test.pattern = 'spec/**/*_spec.rb'
test.rcov_opts += ['--exclude \/Library\/Ruby,spec\/', '--xrefs']
test.verbose = true
end

require 'yard'

YARD::Rake::YardocTask.new(:doc) do |t|
t.options = ['--no-private', '-m', 'markdown', '-o', './doc/public/yard']
end

task :default => :test
7 changes: 7 additions & 0 deletions lib/niceogiri.rb
@@ -0,0 +1,7 @@
%w{
nokogiri

niceogiri/version
niceogiri/core_ext/nokogiri
niceogiri/xml/node
}.each { |f| require f}
44 changes: 44 additions & 0 deletions lib/niceogiri/core_ext/nokogiri.rb
@@ -0,0 +1,44 @@
# @private
module Nokogiri
module XML

# Nokogiri::Node extensions
class Node
# Alias #name to #element_name so we can use #name in an XMPP Stanza context
alias_method :element_name, :name
alias_method :element_name=, :name=

alias_method :attr_set, :[]=
# Override Nokogiri's attribute setter to add the ability to kill an attribute
# by setting it to nil and to be able to lookup an attribute by symbol
#
# @param [#to_s] name the name of the attribute
# @param [#to_s, nil] value the new value or nil to remove it
def []=(name, value)
name = name.to_s
value.nil? ? remove_attribute(name) : attr_set(name, value.to_s)
end

alias_method :nokogiri_xpath, :xpath
# Override Nokogiri's #xpath method to add the ability to use symbols for lookup
# and namespace designation
def xpath(*paths)
paths[0] = paths[0].to_s

if paths.size > 1 && (namespaces = paths.pop).is_a?(Hash)
paths << namespaces.inject({}) { |h,v| h[v[0].to_s] = v[1]; h }
end

nokogiri_xpath *paths
end
alias_method :find, :xpath

# Return the first element at a specified xpath
# @see #xpath
def find_first(*paths)
xpath(*paths).first
end
end

end # XML
end # Nokogiri
3 changes: 3 additions & 0 deletions lib/niceogiri/version.rb
@@ -0,0 +1,3 @@
module Niceogiri
VERSION = "0.0.1"
end
176 changes: 176 additions & 0 deletions lib/niceogiri/xml/node.rb
@@ -0,0 +1,176 @@
module Niceogiri
module XML

# Base XML Node
# All XML classes subclass Node - it allows the addition of helpers
class Node < Nokogiri::XML::Node
# Create a new Node object
#
# @param [String, nil] name the element name
# @param [XML::Document, nil] doc the document to attach the node to. If
# not provided one will be created
# @return a new object with the name and namespace
def self.new(name = nil, doc = nil, ns = nil)
super(name.to_s, (doc || Nokogiri::XML::Document.new)).tap do |node|
node.document.root = node unless doc
node.namespace = self.ns if ns
end
end

# Helper method to read an attribute
#
# @param [#to_sym] attr_name the name of the attribute
# @param [String, Symbol, nil] to_call the name of the method to call on
# the returned value
# @return nil or the value
def read_attr(attr_name, to_call = nil)
val = self[attr_name.to_sym]
val && to_call ? val.__send__(to_call) : val
end

# Helper method to write a value to an attribute
#
# @param [#to_sym] attr_name the name of the attribute
# @param [#to_s] value the value to set the attribute to
def write_attr(attr_name, value)
self[attr_name.to_sym] = value
end

# Helper method to read the content of a node
#
# @param [#to_sym] node the name of the node
# @param [String, Symbol, nil] to_call the name of the method to call on
# the returned value
# @return nil or the value
def read_content(node, to_call = nil)
val = content_from node.to_sym
val && to_call ? val.__send__(to_call) : val
end

# @private
alias_method :nokogiri_namespace=, :namespace=
# Attach a namespace to the node
#
# @overload namespace=(ns)
# Attach an already created XML::Namespace
# @param [XML::Namespace] ns the namespace object
# @overload namespace=(ns)
# Create a new namespace and attach it
# @param [String] ns the namespace uri
# @overload namespace=(namespaces)
# Createa and add new namespaces from a hash
# @param [Hash] namespaces a hash of prefix => uri pairs
def namespace=(namespaces)
case namespaces
when Nokogiri::XML::Namespace
self.nokogiri_namespace = namespaces
when String
self.add_namespace nil, namespaces
when Hash
self.add_namespace nil, ns if ns = namespaces.delete(nil)
namespaces.each do |p, n|
ns = self.add_namespace p, n
self.nokogiri_namespace = ns
end
end
end

# Helper method to get the node's namespace
#
# @return [XML::Namespace, nil] The node's namespace object if it exists
def namespace_href
namespace.href if namespace
end

# Remove a child with the name and (optionally) namespace given
#
# @param [String] name the name or xpath of the node to remove
# @param [String, nil] ns the namespace the node is in
def remove_child(name, ns = nil)
child = xpath(name, ns).first
child.remove if child
end

# Remove all children with a given name regardless of namespace
#
# @param [String] name the name of the nodes to remove
def remove_children(name)
xpath("./*[local-name()='#{name}']").remove
end

# The content of the named node
#
# @param [String] name the name or xpath of the node
# @param [String, nil] ns the namespace the node is in
# @return [String, nil] the content of the node
def content_from(name, ns = nil)
child = xpath(name, ns).first
child.content if child
end

# Sets the content for the specified node.
# If the node exists it is updated. If not a new node is created
# If the node exists and the content is nil, the node will be removed
# entirely
#
# @param [String] node the name of the node to update/create
# @param [String, nil] content the content to set within the node
def set_content_for(node, content = nil)
if content
child = xpath(node).first
self << (child = Node.new(node, self.document)) unless child
child.content = content
else
remove_child node
end
end

alias_method :copy, :dup

# Inherit the attributes and children of an XML::Node
#
# @param [XML::Node] node the node to inherit
# @return [self]
def inherit(node)
set_namespace node.namespace if node.namespace
inherit_attrs node.attributes
node.children.each do |c|
self << (n = c.dup)
ns = n.namespace_definitions.find { |ns| ns.prefix == c.namespace.prefix }
n.namespace = ns if ns
end
self
end

# Inherit a set of attributes
#
# @param [Hash] attrs a hash of attributes to set on the node
# @return [self]
def inherit_attrs(attrs)
attrs.each { |name, value| self[name] = value }
self
end

# The node as XML
#
# @return [String] XML representation of the node
def inspect
self.to_xml
end

# Check that a set of fields are equal between nodes
#
# @param [Node] other the other node to compare against
# @param [*#to_s] fields the set of fields to compare
# @return [Fixnum<-1,0,1>]
def eql?(o, *fields)
o.is_a?(self.class) && fields.all? { |f| self.__send__(f) == o.__send__(f) }
end

# @private
def ==(o)
eql?(o)
end
end # Node
end # XML
end # Niceogiri
30 changes: 30 additions & 0 deletions niceogiri.gemspec
@@ -0,0 +1,30 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "niceogiri/version"

Gem::Specification.new do |s|
s.name = "Niceogiri"
s.version = Niceogiri::VERSION
s.authors = ["Ben Langfeld", "Jeff Smick"]
s.email = ["ben@langfeld.me", "sprsquish@gmail.com"]
s.homepage = "https://github.com/benlangfeld/Niceogiri"
s.summary = %q{Some additional niceties atop Nokogiri}
s.description = %q{Make dealing with XML less painful}

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.rdoc_options = %w{--charset=UTF-8}
s.extra_rdoc_files = %w{LICENSE README.md}

s.add_dependency("nokogiri", [">= 1.4.0"])

s.add_development_dependency("minitest", ["~> 1.7.1"])
s.add_development_dependency("bundler", ["~> 1.0.0"])
s.add_development_dependency("rcov", ["~> 0.9.9"])
s.add_development_dependency("yard", ["~> 0.6.1"])
s.add_development_dependency("bluecloth", ["~> 2.1.0"])
s.add_development_dependency("rake")
end

0 comments on commit 573499d

Please sign in to comment.