ayril 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ # Copyright (C) 2011 by Robert Lowe <rob[!]iblargz.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Ayril
22
+ module Version
23
+ MAJOR = 0
24
+ MINOR = 1
25
+ PATCH = 0
26
+ BUILD = nil
27
+
28
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2011 by Wilson Lee <kourge[!]gmail.com>, Robert Lowe <rob[!]iblargz.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Ayril
22
+ class XMLDocument < NSXMLDocument
23
+ include XMLNode::NodeManipulation
24
+ include XMLNode::NodeTraversal
25
+
26
+ def self.new(data, error=nil)
27
+ path = data.dup
28
+ path = NSURL.fileURLWithPath data.path if data.kind_of? File
29
+ if path.kind_of? NSURL
30
+ XMLDocument.alloc.initWithContentsOfURL path, options: 0, error: error
31
+ elsif path.kind_of? XMLElement
32
+ XMLDocument.alloc.initWithRootElement path
33
+ elsif path.kind_of? String
34
+ XMLDocument.alloc.initWithXMLString path, options: 0, error: error
35
+ end
36
+ end
37
+
38
+ def self.replacementClassForClass(currentClass)
39
+ return {
40
+ NSXMLNode => XMLNode,
41
+ NSXMLElement => XMLElement,
42
+ NSXMLDocument => XMLDocument,
43
+ NSXMLDTD => XMLDTD,
44
+ NSXMLDTDNode => XMLDTDNode
45
+ }[currentClass]
46
+ end
47
+
48
+ forward :to_s, :XMLString
49
+
50
+ def inspect
51
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}>"
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,75 @@
1
+ # Copyright (C) 2011 by Wilson Lee <kourge[!]gmail.com>, Robert Lowe <rob[!]iblargz.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Ayril
22
+ class XMLElement < NSXMLElement
23
+
24
+ autoload :XMLCSSHash, 'ayril/xml_element/xml_css_hash'
25
+ autoload :XMLAttributeHash, 'ayril/xml_element/xml_attribute_hash'
26
+
27
+ autoload :ElementManipulation, 'ayril/xml_element/element_manipulation'
28
+ autoload :ElementAttributeManipulation, 'ayril/xml_element/element_attribute_manipulation'
29
+ autoload :ElementClassnameManipulation, 'ayril/xml_element/element_classname_manipulation'
30
+ autoload :ElementStyleManipulation, 'ayril/xml_element/element_style_manipulation'
31
+
32
+ include XMLNode::NodeManipulation
33
+ include XMLNode::NodeTraversal
34
+
35
+ include ElementManipulation
36
+ include ElementAttributeManipulation
37
+ include ElementClassnameManipulation
38
+ include ElementStyleManipulation
39
+
40
+ @@id_counter = 0
41
+ attr_accessor :id_counter
42
+
43
+ def self.new(name, attributes={})
44
+ if attributes.empty? and name.include? "<"
45
+ self.alloc.initWithXMLString name, error: nil
46
+ else
47
+ XMLNode.elementWithName name, children: nil, attributes: attributes
48
+ end
49
+ end
50
+
51
+ def kind; NSXMLElementKind end
52
+
53
+ def initWithName(name)
54
+ self.class.alloc.tap { |e| e.name = name }
55
+ end
56
+
57
+ def initWithName(name, stringValue: string)
58
+ self.initWithName(name).tap { |e| e.stringValue = string }
59
+ end
60
+
61
+ def initWithName(name, URI: uri)
62
+ self.initWithName(name).tap { |e| e.URI = uri }
63
+ end
64
+
65
+ def initWithXMLString(string, error: error)
66
+ d = XMLDocument.alloc.initWithXMLString(string, options: 0, error: nil)
67
+ d.maybe(:rootElement).tap { |n| n.maybe :detach }
68
+ end
69
+
70
+ def inspect
71
+ attributes = self.attribute.tap { |a| a.sync }
72
+ "#<#{self.class}<#{self.name}#{attributes.maybe(:empty?) ? '' : ' '}#{attributes}>>"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,61 @@
1
+ # Copyright (C) 2011 by Wilson Lee <kourge[!]gmail.com>, Robert Lowe <rob[!]iblargz.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Ayril
22
+ class XMLElement
23
+ module ElementAttributeManipulation
24
+ def attribute
25
+ @attributes.nil? ? (@attributes = XMLElement::XMLAttributeHash.new self) : @attributes
26
+ end
27
+ alias :attr :attribute
28
+
29
+ def attribute=(hash); self.setAttributesAsDictionary hash end
30
+ alias :attr= :attribute=
31
+ alias :set :attribute=
32
+
33
+ def read_attribute(k); self.attributeForName(k.to_s).maybe(:stringValue) end
34
+ alias :get_attribute :read_attribute
35
+ alias :[] :read_attribute
36
+
37
+ def write_attribute(k, v=nil)
38
+ if v.nil? and k.kind_of? Hash
39
+ k.each { |a, b| self.write_attribute a.to_s, b } unless k.empty?
40
+ return self
41
+ end
42
+ attr = self.attributeForName(k)
43
+ if attr.nil?
44
+ self.addAttribute XMLNode.attributeWithName(k.to_s, stringValue: v)
45
+ else
46
+ attr.stringValue = v
47
+ end
48
+ self
49
+ end
50
+ alias :add_attribute :write_attribute
51
+ alias :set_attribute :write_attribute
52
+ alias :[]= :write_attribute
53
+
54
+ def remove_attribute(a) self.removeAttributeForName(a.to_s); self.sync end
55
+ alias :delete_attribute :remove_attribute
56
+
57
+ def has_attribute?(k); not self.attributeForName(k.to_s).nil? end
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,34 @@
1
+ module Ayril
2
+ class XMLElement
3
+ module ElementClassnameManipulation
4
+ def has_class_name?(class_name)
5
+ classes = self.read_attribute "class"
6
+ !!(classes.length > 0 and (classes == class_name or
7
+ classes =~ /(^|\s)#{class_name}(\s|$)/))
8
+ end
9
+
10
+ def add_class_name(class_name)
11
+ if not self.has_class_name? class_name
12
+ current = if not self.has_attribute? "class" then ''
13
+ else self.read_attribute("class") end
14
+ end
15
+ self.write_attribute "class", (current + ((current == '') ? '' : ' ') + class_name)
16
+ self
17
+ end
18
+
19
+ def remove_class_name(class_name)
20
+ return self if not self.has_attribute? "class"
21
+ string_value = self.read_attribute("class").sub(/(^|\s+)#{class_name}(\s+|$)/, ' ').strip
22
+ string_value == '' ? self.remove_attribute("class")
23
+ : self.write_attribute("class", string_value)
24
+ self.tap { |s| s.attribute.sync; s.class_names.sync }
25
+ end
26
+
27
+ def toggle_class_name(class_name)
28
+ if self.has_class_name? class_name
29
+ then self.remove_class_name class_name
30
+ else self.add_class_name class_name end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,85 @@
1
+ # Copyright (C) 2011 by Wilson Lee <kourge[!]gmail.com>, Robert Lowe <rob[!]iblargz.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Ayril
22
+ class XMLElement
23
+ module ElementManipulation
24
+ def insert(insertions)
25
+ insertions = { :bottom => insertions } if insertions.kind_of? String or
26
+ insertions.kind_of? Integer or insertions.kind_of? XMLElement or
27
+ (insertions.respond_to? :to_element or insertions.respond_to? :to_html)
28
+
29
+ insertions.each do |position, content|
30
+ position.downcase! if position.kind_of? String
31
+ insert = {
32
+ :before => lambda { |element, node|
33
+ element.parent.insertChild node, atIndex: element.index
34
+ },
35
+ :top => lambda { |element, node|
36
+ element.insertChild node, atIndex: 0
37
+ },
38
+ :bottom => lambda { |element, node|
39
+ element.addChild node
40
+ },
41
+ :after => lambda { |element, node|
42
+ element.parent.insertChild node, atIndex: element.index + 1
43
+ }
44
+ }[position = position.to_sym]
45
+
46
+ content = content.to_element if content.respond_to? :to_element
47
+ (insert.call(self, content); next) if content.kind_of? XMLElement
48
+
49
+ content = content.respond_to?(:to_html) ? content.to_html : content.to_s
50
+ children = XMLElement.alloc.initWithXMLString("<root>#{content}</root>", error: nil).children
51
+
52
+ children.reverse! if position == :top or position == :after
53
+ children.each { |child| child.detach; insert.call self, child }
54
+ end
55
+ self
56
+ end
57
+
58
+ def append(e) self.insert :bottom => e end
59
+ def prepend(e) self.insert :top => e end
60
+
61
+ def wrap(wrapper=nil, attributes={})
62
+ if wrapper.kind_of? XMLElement
63
+ wrapper.write_attribute attributes
64
+ elsif wrapper.kind_of? String
65
+ wrapper = XMLElement.new wrapper, attributes
66
+ else
67
+ wrapper = XMLElement.new 'div', attributes
68
+ end
69
+ self.replace wrapper if self.parent
70
+ wrapper.addChild self
71
+ wrapper
72
+ end
73
+
74
+ def identify
75
+ id = self.read_attribute "id"
76
+ return id unless id.nil?
77
+ begin
78
+ id = "anonymous_element_#{XMLElement::id_counter += 1}"
79
+ end while self.rootDocument.select("##{id}").any?
80
+ self.write_attribute "id", id
81
+ id
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,11 @@
1
+ module Ayril
2
+ class XMLElement
3
+ module ElementStyleManipulation
4
+ def style; XMLElement::XMLCSSHash.new self end
5
+ def style=(h) self.style.replace h end
6
+
7
+ def get_style(prop) self.style[style] end
8
+ def set_style(style, value) self.style[style] = value end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,60 @@
1
+ module Ayril
2
+ class XMLElement
3
+ class XMLAttributeHash < Hash
4
+ def initialize(element)
5
+ @element = element
6
+ self.sync
7
+ end
8
+
9
+ def sync
10
+ cache = {}
11
+ @element.attributes.each { |a| cache[a.name] = a.stringValue } if not @element.attributes.nil?
12
+ self.delete_if { true }.merge! cache
13
+ end
14
+
15
+ def store(k, v)
16
+ attr = @element.attributeForName k
17
+ if not attr.nil?
18
+ attr.stringValue = v
19
+ else
20
+ @element.addAttribute XMLNode.attributeWithName(k, stringValue: v)
21
+ end
22
+ super k, v
23
+ end
24
+ alias :set :store
25
+ alias :[]= :store
26
+
27
+ def fetch(k); @element.attributeForName(k).maybe :stringValue end
28
+ alias :get :fetch
29
+ alias :[] :fetch
30
+
31
+ def has_key?(k); not @element.attributeForName(k).nil? end
32
+ alias :has? :has_key?
33
+ alias :include? :has_key?
34
+ alias :key? :has_key?
35
+ alias :member? :has_key?
36
+
37
+ def delete(k); @element.removeAttributeForName k; super k end
38
+ alias :remove :delete
39
+ alias :- :delete
40
+
41
+ def _delete_if(&blk); self.each { |k, v| self.delete k if blk.call k, v } end
42
+ def delete_if(&blk); self._delete_if &blk; self end
43
+
44
+ def reject!(&blk)
45
+ old = self.dup; self._delete_if &blk
46
+ (self == old) ? nil : self
47
+ end
48
+
49
+ def replace(hash); @element.setAttributesAsDictionary hash; super hash end
50
+ def clear; self.replace {} end
51
+
52
+ def merge!(hash); hash.each { |k, v| self[k] = v }; self end
53
+ alias :update! :merge!
54
+ alias :+ :merge!
55
+
56
+ def to_s; self.map { |k, v| "#{k}=\"#{v}\"" }.join ' ' end
57
+ def inspect; "#<#{self.class} #{self.to_s}>" end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,47 @@
1
+ module Ayril
2
+ class XMLElement
3
+ class XMLCSSHash < Hash
4
+ def initialize(element)
5
+ if not (@element = element).has_attribute? "style"
6
+ @element.write_attribute "style", ''
7
+ end
8
+ css = @element.read_attribute "style"
9
+ css.gsub(/\n/, '').split(';').invoke(:strip).compact.each do |property|
10
+ property.split(':').tap { |p| self[p.shift] = p.join(':').strip }
11
+ end.tap { sync }
12
+ end
13
+
14
+ def to_css; self.map { |k, v| "#{k}: #{v}" }.join "; " end
15
+ alias :to_s :to_css
16
+
17
+ def inspect; "#<#{self.class} {#{self.to_css}}>" end
18
+
19
+ def store(k, v) super(k, v).tap { sync } end
20
+ alias :[]= :store
21
+
22
+ def fetch(k) super(k).tap { sync } end
23
+ alias :[] :fetch
24
+
25
+ def delete(k) super(k).tap { sync } end
26
+ alias :- :delete
27
+
28
+ def delete_if(&blk) super(&blk).tap { sync } end
29
+ def reject!(&blk) super(&blk).tap { sync } end
30
+ def replace(h) super(h).tap { sync } end
31
+ def clear; super.tap { sync } end
32
+
33
+ def merge!(h) super(h).tap { sync } end
34
+ alias :update! :merge!
35
+ alias :+ :merge!
36
+
37
+ def sync
38
+ @element.removeAttributeForName("style") and return if self.size == 0
39
+ @element.write_attribute "style", self.to_css
40
+ end
41
+
42
+ alias :include? :has_key?
43
+ alias :key? :has_key?
44
+ alias :member? :has_key?
45
+ end
46
+ end
47
+ end