dominikh-tidy_ffi 0.1.2

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.
data/CHANGELOG ADDED
@@ -0,0 +1,7 @@
1
+ v0.1.1. Fixes for new version of FFI gem
2
+ v0.1.0. Clean class method.
3
+ v0.0.4. Options validation
4
+ v0.0.3. Add method “errors” to return errors after cleanup
5
+ v0.0.2. Do not require matchy, rr and context as development dependencies. A user does not need them.
6
+ v0.0.1. Options support.
7
+ v0.0.0. Initial release.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2009 Eugene Pimenov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/Manifest ADDED
@@ -0,0 +1,16 @@
1
+ CHANGELOG
2
+ LICENSE
3
+ Manifest
4
+ README.rdoc
5
+ Rakefile
6
+ lib/tidy_ffi/interface.rb
7
+ lib/tidy_ffi/lib_tidy.rb
8
+ lib/tidy_ffi/options_container.rb
9
+ lib/tidy_ffi/tidy.rb
10
+ lib/tidy_ffi/tidy_ffi_extensions.rb
11
+ lib/tidy_ffi.rb
12
+ test/test_helper.rb
13
+ test/test_lowlevel.rb
14
+ test/test_options.rb
15
+ test/test_simple.rb
16
+ tidy_ffi.gemspec
data/README.rdoc ADDED
@@ -0,0 +1,31 @@
1
+ = Tidy FFI
2
+
3
+ == What is it all about?
4
+
5
+ I wanna clean and simple tidy library. For example:
6
+ TidyFFI::Tidy.new('a string').clean
7
+
8
+ For now it can't do anything else than clean (and saves errors from it) :)
9
+
10
+ == Options
11
+
12
+ You can use different ways to set up options. These examples are produces the same output:
13
+
14
+ TidyFFI::Tidy.default_options.show_body_only = true
15
+ TidyFFI::Tidy.new('test').clean
16
+
17
+ TidyFFI::Tidy.with_options(:show_body_only => true).new('test').clean
18
+
19
+ tidy = TidyFFI::Tidy.new('test')
20
+ tidy.options.show_body_only = true
21
+ tidy.clean
22
+
23
+ TidyFFI::Tidy.new('test', :show_body_only => true).clean
24
+
25
+ TidyFFI::Tidy.clean('test', :show_body_only => 1)
26
+
27
+ == Links
28
+
29
+ * Source code: http://github.com/libc/tidy_ffi
30
+ * Bug tracker: http://rubyforge.org/tracker/?atid=30230&group_id=7805&func=browse
31
+ * Rubyforge project: http://rubyforge.org/projects/tidy-ffi
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ begin
3
+ require 'echoe'
4
+ Echoe.new('tidy_ffi') do |p|
5
+ p.author = 'Eugene Pimenov'
6
+ p.summary = 'Tidy library interface via FFI'
7
+ p.url = 'http://github.com/libc/tidy_ffi'
8
+ p.runtime_dependencies = ['ffi >=0.3.5']
9
+ # p.development_dependencies = ['rr', 'matchy', 'context']
10
+ p.project = 'tidy-ffi'
11
+ p.email = 'libc@libc.st'
12
+ p.rdoc_pattern = /^(lib|bin|tasks|ext)|^README\.rdoc|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
13
+ p.retain_gemspec = true
14
+ end
15
+
16
+ # My common error
17
+ task :rdoc => :doc do; end
18
+ rescue LoadError => boom
19
+ puts "You are missing a dependency required for meta-operations on this gem."
20
+ puts "#{boom.to_s.capitalize}."
21
+
22
+ desc 'No effect.'
23
+ task :default do; end
24
+ end
data/lib/tidy_ffi.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'ffi'
3
+
4
+ module TidyFFI
5
+ self.autoload :LibTidy, 'tidy_ffi/lib_tidy'
6
+ self.autoload :Interface, 'tidy_ffi/interface'
7
+ end
8
+
9
+ require 'tidy_ffi/options_container'
10
+ require 'tidy_ffi/tidy'
11
+ require 'tidy_ffi/tidy_ffi_extensions'
@@ -0,0 +1,186 @@
1
+ # Low level interface to libtidy.
2
+ class TidyFFI::Interface
3
+ LibTidy = TidyFFI::LibTidy
4
+
5
+ # Returns a TidyFFI::Interface with initialized interface.
6
+ def self.with_doc
7
+ doc = LibTidy.tidyCreate
8
+ nd = new(doc)
9
+ nd.with_redirected_error_buffer { yield nd }
10
+ ensure
11
+ LibTidy.tidyRelease(doc)
12
+ end
13
+
14
+ def initialize(doc) #:nodoc:
15
+ @doc = doc
16
+ end
17
+
18
+ # Apply options
19
+ def apply_options(options)
20
+ options.each do |key, value|
21
+ k = key.to_s.gsub('_', '-')
22
+
23
+ option = LibTidy.tidyGetOptionByName(@doc, k)
24
+ raise ArgumentError, "don't know about option #{key}" if option.null?
25
+ id = LibTidy.tidyOptGetId(option)
26
+ raise ArgumentError, "can't setup option #{key} to #{value}" if LibTidy.tidyOptSetValue(@doc, id, value.to_s) == 0
27
+ end
28
+ end
29
+
30
+ # Sets string to tidy
31
+ def string=(str)
32
+ LibTidy.tidyParseString(@doc, str)
33
+ end
34
+
35
+ # Cleans string
36
+ def clean
37
+ @output = nil
38
+ LibTidy.tidyCleanAndRepair(@doc)
39
+ end
40
+ alias :clean_and_repair :clean
41
+ alias :repair :clean
42
+
43
+ # Returns output from tidy library
44
+ def output
45
+ @output ||= begin
46
+ with_buffer_pointer do |buf|
47
+ LibTidy.tidySaveBuffer(@doc, buf)
48
+ buf[:bp]
49
+ end
50
+ end
51
+ end
52
+
53
+ def errors
54
+ @error_buffer[:bp]
55
+ end
56
+
57
+ # Redirects error buffer
58
+ def with_redirected_error_buffer
59
+ with_buffer_pointer do |buf|
60
+ @error_buffer = buf
61
+ LibTidy.tidySetErrorBuffer(@doc, buf)
62
+ yield
63
+ end
64
+ ensure
65
+ @error_buffer = nil
66
+ end
67
+
68
+ # Yields block with new buffer
69
+ def with_buffer_pointer
70
+ buf = tidy_buf_object.new
71
+ yield buf
72
+ ensure
73
+ LibTidy.tidyBufFree(buf)
74
+ end
75
+
76
+ def tidy_buf_object
77
+ @tidy_buf_object ||= begin
78
+ TidyFFI::LibTidy::TidyBufWithAllocator
79
+ end
80
+ end
81
+ private :tidy_buf_object
82
+
83
+ class <<self
84
+ # Returns enumeration for opt.
85
+ #
86
+ # Some tidy options might try to trespass as integer, and in order to caught
87
+ # perpertraitors we need to call tidyOptGetPickList
88
+ def pick_list_for(opt)
89
+ iterator = LibTidy.tidyOptGetPickList(opt)
90
+
91
+ return nil if iterator.null?
92
+
93
+ pick_list = []
94
+
95
+ FFI::MemoryPointer.new(:pointer, 1) do |pointer|
96
+ pointer.put_pointer(0, iterator)
97
+ until iterator.null?
98
+ pick_list << LibTidy.tidyOptGetNextPick(opt, pointer)
99
+ iterator = pointer.get_pointer(0)
100
+ end
101
+ end
102
+
103
+ pick_list
104
+ end
105
+ private :pick_list_for
106
+
107
+ # Loads default options.
108
+ def load_default_options
109
+ return if @default_options
110
+
111
+ doc = LibTidy.tidyCreate
112
+ iterator = LibTidy.tidyGetOptionList(doc)
113
+
114
+ @default_options = {}
115
+
116
+ FFI::MemoryPointer.new(:pointer, 1) do |pointer|
117
+ pointer.put_pointer(0, iterator)
118
+
119
+ until iterator.null?
120
+ opt = LibTidy.tidyGetNextOption(doc, pointer)
121
+
122
+ option = {}
123
+
124
+ option[:name] = LibTidy.tidyOptGetName(opt).gsub('-', '_').intern
125
+ option[:readonly?] = LibTidy.tidyOptIsReadOnly(opt) != 0
126
+ option[:type] = LibTidy::TIDY_OPTION_TYPE[LibTidy.tidyOptGetType(opt)]
127
+ option[:default] = case option[:type]
128
+ when :string
129
+ (LibTidy.tidyOptGetDefault(opt) rescue "")
130
+ when :integer
131
+ if pick_list = pick_list_for(opt)
132
+ option[:type] = :enum
133
+ option[:values] = pick_list
134
+ pick_list[LibTidy.tidyOptGetDefaultInt(opt)]
135
+ else
136
+ LibTidy.tidyOptGetDefaultInt(opt)
137
+ end
138
+ when :boolean
139
+ LibTidy.tidyOptGetDefaultBool(opt) != 0
140
+ end
141
+
142
+ @default_options[option[:name]] = option
143
+
144
+ iterator = pointer.get_pointer(0)
145
+ end
146
+
147
+ end
148
+ @default_options.freeze
149
+ ensure
150
+ LibTidy.tidyRelease(doc)
151
+ end
152
+ private :load_default_options
153
+ end
154
+
155
+ # Returns a hash that represents default options for tidy.
156
+ # Key for hash is the option name, value is also a hash...
157
+ # Possible values are:
158
+ # * :type - either :string, :integer, :boolean or :enum
159
+ # * :readonly?
160
+ # * :default - default value of an option
161
+ # * :values - possible values for :enum
162
+ # * :name
163
+ def self.default_options
164
+ @default_options ||= load_default_options
165
+ end
166
+
167
+ # Returns true if value is valid for +option+ and false otherwise.
168
+ def self.option_valid?(option, value)
169
+ return false unless spec = default_options[option]
170
+
171
+ case spec[:type]
172
+ when :boolean
173
+ true == value || false == value || value == 0 || value == 1 || %w(on off true false 0 1 yes no).include?(value.downcase)
174
+ when :integer
175
+ Integer === value || !!(value =~ /^\d+$/)
176
+ when :enum
177
+ if Integer === value
178
+ !!spec[:values][value]
179
+ else
180
+ spec[:values].include?(value)
181
+ end
182
+ when :string
183
+ String === value || Symbol === value
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,67 @@
1
+ # Very low level interface to tidy
2
+
3
+ # This file must be lazy loaded!
4
+ class TidyFFI::LibTidy #:nodoc:
5
+ extend FFI::Library
6
+ ffi_lib TidyFFI.library_path
7
+
8
+ attach_function :tidyReleaseDate, [], :string
9
+
10
+ attach_function :tidyCreate, [], :pointer
11
+ attach_function :tidyRelease, [:pointer], :void
12
+
13
+ attach_function :tidyCleanAndRepair, [:pointer], :int
14
+ attach_function :tidyRunDiagnostics, [:pointer], :int
15
+
16
+ attach_function :tidyParseString, [:pointer, :string], :int
17
+
18
+ attach_function :tidySaveBuffer, [:pointer, :pointer], :int
19
+
20
+ attach_function :tidySetErrorBuffer, [:pointer, :pointer], :int
21
+
22
+ attach_function :tidyBufFree, [:pointer], :void
23
+
24
+ attach_function :tidyGetOptionByName, [:pointer, :string], :pointer
25
+ attach_function :tidyOptGetId, [:pointer], :int
26
+ attach_function :tidyOptSetValue, [:pointer, :int, :string], :int
27
+
28
+ # iterators
29
+ attach_function :tidyGetOptionList, [:pointer], :pointer
30
+ attach_function :tidyGetNextOption, [:pointer, :pointer], :pointer
31
+ attach_function :tidyOptGetName, [:pointer], :string
32
+ attach_function :tidyOptGetType, [:pointer], :int
33
+ attach_function :tidyOptGetDefault, [:pointer], :string
34
+ attach_function :tidyOptGetDefaultInt, [:pointer], :ulong
35
+ attach_function :tidyOptGetDefaultBool, [:pointer], :int
36
+ attach_function :tidyOptIsReadOnly, [:pointer], :int
37
+ attach_function :tidyOptGetPickList, [:pointer], :pointer
38
+ attach_function :tidyOptGetNextPick, [:pointer, :pointer], :string
39
+
40
+ #types
41
+ # /** Option data types
42
+ # */
43
+ # typedef enum
44
+ # {
45
+ # TidyString, /**< String */
46
+ # TidyInteger, /**< Integer or enumeration */
47
+ # TidyBoolean /**< Boolean flag */
48
+ # } TidyOptionType;
49
+ TIDY_OPTION_TYPE = [:string, :integer, :boolean].freeze
50
+
51
+ end
52
+
53
+ class TidyFFI::LibTidy::TidyBuf < FFI::Struct #:nodoc:
54
+ layout :bp, :string,
55
+ :size, :uint,
56
+ :allocated, :uint,
57
+ :next, :uint
58
+ end
59
+
60
+ class TidyFFI::LibTidy::TidyBufWithAllocator < FFI::Struct #:nodoc:
61
+ layout :allocator, :pointer,
62
+ :bp, :string,
63
+ :size, :uint,
64
+ :allocated, :uint,
65
+ :next, :uint
66
+ end
67
+
@@ -0,0 +1,90 @@
1
+ class TidyFFI::OptionsContainer #:nodoc:
2
+
3
+ def initialize(ops = nil)
4
+ if ops
5
+ @options = ops.to_hash!
6
+ else
7
+ @options = {}
8
+ end
9
+ end
10
+
11
+ def to_hash!
12
+ @options.dup
13
+ end
14
+
15
+ def merge_with_options(options)
16
+ options.each do |key, val|
17
+ key = key.intern unless Symbol === key
18
+ validate_option(key, val)
19
+ @options[key] = val
20
+ end
21
+ end
22
+
23
+ def ==(obj)
24
+ if obj.is_a?(Hash)
25
+ @options == obj
26
+ elsif obj.is_a?(OptionsContainer)
27
+ obj == @options
28
+ else
29
+ false
30
+ end
31
+ end
32
+
33
+ def clear!
34
+ @options = {}
35
+ self
36
+ end
37
+
38
+ def method_missing(method, *args)
39
+ if method.to_s =~ /=$/
40
+ key, val = method.to_s.sub(/=$/, '').intern, args.first
41
+ validate_option(key, val)
42
+ @options[key] = val
43
+ else
44
+ @options[method]
45
+ end
46
+ end
47
+
48
+ # It's a kinda bad method: it uses TidyFFI::Interface.option_valid and TidyFFI::Tidy.validate_options?
49
+ # Also it do second lookup into default options
50
+ def validate_option(key, value)
51
+ if TidyFFI::Tidy.validate_options? && !TidyFFI::Interface.option_valid?(key, value)
52
+ if TidyFFI::Interface.default_options[key]
53
+ raise TidyFFI::Tidy::InvalidOptionValue, "#{value} is not valid for #{key}"
54
+ else
55
+ raise TidyFFI::Tidy::InvalidOptionName, "#{key} is invalid option name"
56
+ end
57
+ end
58
+ end
59
+
60
+ class Proxy #:nodoc:
61
+ attr_reader :options
62
+
63
+ define_method :new do |*args|
64
+ @obj.new(args.first, options.to_hash!.merge(args[1] || {}))
65
+ end
66
+
67
+ def clean(str, opts = {})
68
+ @obj.clean(str, options.to_hash!.merge(opts))
69
+ end
70
+
71
+ def initialize(obj, options1, options2)
72
+ @obj = obj
73
+ @options = TidyFFI::OptionsContainer.new(options1)
74
+ @options.merge_with_options(options2)
75
+ end
76
+
77
+ def with_options(options)
78
+ Proxy.new(@obj, @options, options)
79
+ end
80
+
81
+ def clear!
82
+ @options.clear!
83
+ self
84
+ end
85
+
86
+ def method_missing(meth, *args)
87
+ @obj.send(meth, *args)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,83 @@
1
+ # Clean and simple interface to Tidy
2
+ class TidyFFI::Tidy
3
+ OptionsContainer = TidyFFI::OptionsContainer
4
+ class InvalidOptionName < ArgumentError; end
5
+ class InvalidOptionValue < ArgumentError; end
6
+
7
+ #Initializing object.
8
+ #
9
+ #* str is a string to tidy
10
+ #* options are options for tidy
11
+ def initialize(str, options = {})
12
+ @string = str
13
+ @options = OptionsContainer.new(self.class.default_options)
14
+ self.options = options
15
+ end
16
+
17
+ # Returns cleaned string
18
+ def clean
19
+ @clean ||= TidyFFI::Interface.with_doc do |doc|
20
+ doc.apply_options(@options.to_hash!)
21
+ doc.string = @string
22
+ doc.clean
23
+ @errors = doc.errors
24
+ doc.output
25
+ end
26
+ end
27
+
28
+ # Returns cleaned string
29
+ def self.clean(str, options = {})
30
+ new(str, options).clean
31
+ end
32
+
33
+ # Returns errors for string
34
+ def errors
35
+ @errors ||= begin
36
+ clean
37
+ @errors
38
+ end
39
+ end
40
+
41
+ # Assigns options for tidy.
42
+ # It merges options, not deletes old ones.
43
+ # tidy.options= {:wrap_asp => true}
44
+ # tidy.options= {:show_body_only => true}
45
+ # Will send to tidy both options.
46
+ def options=(options)
47
+ @options.merge_with_options(options)
48
+ end
49
+
50
+ # Proxy for options. Supports set and get
51
+ #
52
+ # tidy.options.show_body_only #=> nil
53
+ # tidy.options.show_body_only = true
54
+ # tidy.options.show_body_only #=> true
55
+ def options
56
+ @options
57
+ end
58
+
59
+ class <<self
60
+ # Default options for tidy. Works just like options method
61
+ def default_options
62
+ @default_options ||= OptionsContainer.new
63
+ end
64
+
65
+ # Default options for tidy. Works just like options= method
66
+ def default_options=(options)
67
+ @default_options.merge_with_options(options)
68
+ end
69
+
70
+ # Returns a proxy class with options.
71
+ # Example:
72
+ # TidyFFI::Tidy.with_options(:show_body_only => true).with_options(:wrap_asp => true).new('test)
73
+ def with_options(options)
74
+ OptionsContainer::Proxy.new(self, @default_options, options)
75
+ end
76
+
77
+ # When true it validates name and option type (default is true).
78
+ def validate_options?
79
+ @validate_options != false
80
+ end
81
+ attr_writer :validate_options
82
+ end
83
+ end
@@ -0,0 +1,26 @@
1
+ module TidyFFI::TidyFFIExtensions #:nodoc:
2
+ # Sets path to libtidy.{dylib,so}
3
+ def library_path=(path)
4
+ @libtidy_path = path
5
+ end
6
+
7
+ # Returns path to libtidy.{dylib,so}
8
+ def library_path
9
+ @libtidy_path ||= find_tidy
10
+ end
11
+
12
+ def find_tidy
13
+ fnames = ['libtidy.dylib', 'libtidy.so']
14
+ pathes = []
15
+ pathes += ENV['LD_LIBRARY_PATH'].split(':') if ENV['LD_LIBRARY_PATH']
16
+ pathes += ENV['DYLD_LIBRARY_PATH'].split(':') if ENV['DYLD_LIBRARY_PATH']
17
+ pathes += ENV['PATH'].split(':').reject { |a| a['sbin'] }.map { |a| a.sub('/bin', '/lib') } if ENV['PATH']
18
+ pathes = ['/usr/lib', '/usr/local/lib'] if pathes.size == 0
19
+ for path in pathes.uniq
20
+ fnames.each { |fname| return File.join(path, fname) if File.exists?(File.join(path, fname)) }
21
+ end
22
+ nil
23
+ end
24
+ private :find_tidy
25
+ end
26
+ TidyFFI.extend TidyFFI::TidyFFIExtensions
@@ -0,0 +1,13 @@
1
+ require 'test/unit'
2
+
3
+ require 'tidy_ffi'
4
+
5
+ require 'rubygems'
6
+ require 'rr'
7
+ require 'matchy'
8
+ require 'context'
9
+
10
+ class Test::Unit::TestCase
11
+ alias method_name name unless instance_methods.include?('method_name')
12
+ include RR::Adapters::TestUnit unless instance_methods.include?('stub') || instance_methods.include?(:stub)
13
+ end
@@ -0,0 +1,86 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class TestSimple < Test::Unit::TestCase
4
+ I = TidyFFI::Interface
5
+ context "TidyFFI::Interface" do
6
+ context "default_options" do
7
+ it "returns a hash" do
8
+ I.default_options.is_a?(Hash)
9
+ end
10
+
11
+ it "has show force_output option" do
12
+ I.default_options[:force_output][:name].should == :force_output
13
+ I.default_options[:force_output][:type].should == :boolean
14
+ end
15
+ end
16
+
17
+ context "option_valid" do
18
+ it "returns false when unknown options is specified" do
19
+ I.option_valid?(:gobbledygook, '1').should == false
20
+ end
21
+
22
+ it "accepts yes, no, 1, 0, true, false as boolean values" do
23
+ stub(I).default_options { {:gobbledygook => {:type => :boolean}} }
24
+
25
+ %w{yes no 1 0 true false on off YeS}.each do |val|
26
+ I.option_valid?(:gobbledygook, val).should == true
27
+ end
28
+ I.option_valid?(:gobbledygook, 1).should == true
29
+ I.option_valid?(:gobbledygook, 0).should == true
30
+ I.option_valid?(:gobbledygook, true).should == true
31
+ I.option_valid?(:gobbledygook, false).should == true
32
+
33
+ I.option_valid?(:gobbledygook, "gobbledygook").should == false
34
+ end
35
+
36
+ it "accepts a number as a valid integer value" do
37
+ stub(I).default_options { {:gobbledygook => {:type => :integer}} }
38
+
39
+ I.option_valid?(:gobbledygook, 1).should == true
40
+ I.option_valid?(:gobbledygook, 0).should == true
41
+ I.option_valid?(:gobbledygook, "0").should == true
42
+ I.option_valid?(:gobbledygook, "1").should == true
43
+ I.option_valid?(:gobbledygook, "42").should == true
44
+
45
+ I.option_valid?(:gobbledygook, "gobbledygook").should == false
46
+ I.option_valid?(:gobbledygook, "true").should == false
47
+ end
48
+
49
+ it "accepts any string as a valid string value" do
50
+ stub(I).default_options { {:gobbledygook => {:type => :string}} }
51
+
52
+ I.option_valid?(:gobbledygook, 1).should == false
53
+ I.option_valid?(:gobbledygook, 0).should == false
54
+
55
+ I.option_valid?(:gobbledygook, "0").should == true
56
+ I.option_valid?(:gobbledygook, "1").should == true
57
+ I.option_valid?(:gobbledygook, "42").should == true
58
+ I.option_valid?(:gobbledygook, "gobbledygook").should == true
59
+ I.option_valid?(:gobbledygook, "true").should == true
60
+
61
+ end
62
+
63
+ it "accepts a symbols as a valid string value" do
64
+ stub(I).default_options { {:gobbledygook => {:type => :string}} }
65
+
66
+ I.option_valid?(:gobbledygook, :test).should == true
67
+ end
68
+
69
+ it "accepts number in range as a valid enum value" do
70
+ stub(I).default_options { {:gobbledygook => {:type => :enum, :values => ["one", "two"]}} }
71
+
72
+ I.option_valid?(:gobbledygook, 1).should == true
73
+ I.option_valid?(:gobbledygook, 0).should == true
74
+ I.option_valid?(:gobbledygook, 3).should == false
75
+ end
76
+
77
+ it "accepts string representation of enum value" do
78
+ stub(I).default_options { {:gobbledygook => {:type => :enum, :values => ["one", "two"]}} }
79
+
80
+ I.option_valid?(:gobbledygook, "one").should == true
81
+ I.option_valid?(:gobbledygook, "two").should == true
82
+ I.option_valid?(:gobbledygook, "three").should == false
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,133 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class TestOptions < Test::Unit::TestCase
4
+ T = TidyFFI::Tidy
5
+ context "public interface" do
6
+ [:default_options, :default_options=, :with_options, :validate_options].each do |method|
7
+ it "responds to #{method}" do
8
+ T.respond_to?(method)
9
+ end
10
+ end
11
+ end
12
+
13
+ context "default_options method" do
14
+ before :each do
15
+ T.default_options.clear!
16
+ T.validate_options = false
17
+ end
18
+
19
+ context "equals version" do
20
+ it "passes arguments to default_options.merge_with_options" do
21
+ T.default_options.expects(:merge_with_options)
22
+ T.default_options = {:test => 1, :test2 => 2}
23
+ end
24
+
25
+ it "merges options with existing" do
26
+ T.default_options = {:test => 1, :test2 => 2}
27
+ T.default_options = {:test3 => 3, :test2 => 42}
28
+ T.default_options.should == {:test => 1, :test2 => 42, :test3 => 3}
29
+ end
30
+ end
31
+
32
+ it "has clear! method to clear anything" do
33
+ T.default_options.test = 1
34
+ T.default_options.clear!
35
+ T.default_options.test.should == nil
36
+ end
37
+
38
+ it "saves options" do
39
+ T.default_options.option = 1
40
+ T.default_options.option.should == 1
41
+ end
42
+
43
+ it "sets optons after creation" do
44
+ T.new('test').options.option.should == nil
45
+ T.default_options.option = 1
46
+ T.new('test').options.option.should == 1
47
+ end
48
+ end
49
+
50
+ context "options method" do
51
+ before :each do
52
+ T.validate_options = false
53
+ T.default_options.clear!
54
+ @t = T.new('test')
55
+ end
56
+
57
+ context "equal version" do
58
+ before :each do
59
+ @t.options.clear!
60
+ end
61
+
62
+ it "passes arguments to options.merge_with_options" do
63
+ @t.options.expects(:merge_with_options)
64
+ @t.options = {:test => 1, :test2 => 2}
65
+ end
66
+
67
+ it "merges options with existing" do
68
+ @t.options = {:test => 1, :test2 => 2}
69
+ @t.options = {:test3 => 3, :test2 => 42}
70
+ @t.options.should == {:test => 1, :test2 => 42, :test3 => 3}
71
+ end
72
+ end
73
+
74
+ context "clear! method" do
75
+ it "clears options' options" do
76
+ @t.options.test = 1
77
+ @t.options.clear!
78
+ @t.options.test.should == nil
79
+ end
80
+
81
+ it "clears default_options's options" do
82
+ T.default_options.test = 1
83
+ @t = T.new('test')
84
+ @t.options.clear!
85
+ @t.options.test.should == nil
86
+ end
87
+
88
+ it "clears with_options's options" do
89
+ @t = T.with_options(:test => 1).new('test')
90
+ @t.options.clear!
91
+ @t.options.test.should == nil
92
+ end
93
+ end
94
+
95
+ it "saves options" do
96
+ @t.options.option = 1
97
+ @t.options.option.should == 1
98
+ end
99
+
100
+ it "passes options to libtidy" do
101
+ @t.options.show_body_only = 1
102
+ @t.clean.should == "test\n"
103
+ end
104
+
105
+ it "passes options to clean class method" do
106
+ T.with_options(:show_body_only => true).clean("test").should == "test\n"
107
+ end
108
+ end
109
+
110
+ context "with_options proxy class" do
111
+ before :each do
112
+ T.validate_options = false
113
+ end
114
+
115
+ it "has options method" do
116
+ T.with_options(:test => 1).options.test.should == 1
117
+ end
118
+
119
+ it "has clear! method" do
120
+ T.with_options(:test => 1).clear!.options.test.should == nil
121
+ end
122
+
123
+ it "chain methods" do
124
+ proxy = T.with_options(:test => 1).with_options(:test2 => 2)
125
+ proxy.options.test.should == 1
126
+ proxy.options.test2.should == 2
127
+ end
128
+
129
+ it "passes options to object" do
130
+ T.with_options(:test => 1).new('test').options.test.should == 1
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,52 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class TestSimple < Test::Unit::TestCase
4
+ T = TidyFFI::Tidy
5
+ context "TidyFFI::Tidy" do
6
+ context "public interface" do
7
+ [[:initialize, -2],
8
+ [:clean, 0],
9
+ [:errors, 0]].each do |method, arity|
10
+ it "method #{method} has arity #{arity}" do
11
+ T.instance_method(method).arity.should == arity
12
+ end
13
+ end
14
+ end
15
+
16
+ context "simple cleanup" do
17
+ it "clean up text" do
18
+ T.new("test").clean.should =~ %r{<body>\s+test\s+</body>}
19
+ T.new("test").clean.should =~ %r{<meta name="generator" content=.+?Tidy.+?>}m
20
+
21
+ T.clean("test").should =~ %r{<body>\s+test\s+</body>}
22
+ T.clean("test").should =~ %r{<meta name="generator" content=.+?Tidy.+?>}m
23
+ end
24
+ end
25
+
26
+ context "should have method for errors" do
27
+ it "have method for errors" do
28
+ t = T.new("test")
29
+ t.clean
30
+ t.errors.should == "line 1 column 1 - Warning: missing <!DOCTYPE> declaration\nline 1 column 1 - Warning: plain text isn't allowed in <head> elements\nline 1 column 1 - Warning: inserting missing 'title' element\n"
31
+ end
32
+ end
33
+
34
+
35
+ # Commented out, because of broken upstream matchy gem :(
36
+ # context "options validation" do
37
+ # it "raises error on invalid option name" do
38
+ # TidyFFI::Tidy.validate_options = true
39
+ # lambda do
40
+ # TidyFFI::Tidy.default_options = {:complete_garbage => true}
41
+ # end.should raise_error(TidyFFI::Tidy::InvalidOptionName)
42
+ # end
43
+ #
44
+ # it "raises error on invalid option value" do
45
+ # TidyFFI::Tidy.validate_options = true
46
+ # lambda do
47
+ # TidyFFI::Tidy.default_options = {:force_output => "utter trash"}
48
+ # end.should raise_error(TidyFFI::Tidy::InvalidOptionValue)
49
+ # end
50
+ # end
51
+ end
52
+ end
data/tidy_ffi.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{tidy_ffi}
5
+ s.version = "0.1.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Eugene Pimenov"]
9
+ s.date = %q{2009-06-07}
10
+ s.description = %q{Tidy library interface via FFI}
11
+ s.email = %q{libc@libc.st}
12
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc", "lib/tidy_ffi/interface.rb", "lib/tidy_ffi/lib_tidy.rb", "lib/tidy_ffi/options_container.rb", "lib/tidy_ffi/tidy.rb", "lib/tidy_ffi/tidy_ffi_extensions.rb", "lib/tidy_ffi.rb"]
13
+ s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.rdoc", "Rakefile", "lib/tidy_ffi/interface.rb", "lib/tidy_ffi/lib_tidy.rb", "lib/tidy_ffi/options_container.rb", "lib/tidy_ffi/tidy.rb", "lib/tidy_ffi/tidy_ffi_extensions.rb", "lib/tidy_ffi.rb", "test/test_helper.rb", "test/test_lowlevel.rb", "test/test_options.rb", "test/test_simple.rb", "tidy_ffi.gemspec"]
14
+ s.homepage = %q{http://github.com/libc/tidy_ffi}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Tidy_ffi", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{tidy-ffi}
18
+ s.rubygems_version = %q{1.3.4}
19
+ s.summary = %q{Tidy library interface via FFI}
20
+ s.test_files = ["test/test_helper.rb", "test/test_lowlevel.rb", "test/test_options.rb", "test/test_simple.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<ffi>, [">= 0.3.5"])
28
+ else
29
+ s.add_dependency(%q<ffi>, [">= 0.3.5"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<ffi>, [">= 0.3.5"])
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dominikh-tidy_ffi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Eugene Pimenov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-07 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ffi
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.3.5
24
+ version:
25
+ description: Tidy library interface via FFI
26
+ email: libc@libc.st
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - CHANGELOG
33
+ - LICENSE
34
+ - README.rdoc
35
+ - lib/tidy_ffi/interface.rb
36
+ - lib/tidy_ffi/lib_tidy.rb
37
+ - lib/tidy_ffi/options_container.rb
38
+ - lib/tidy_ffi/tidy.rb
39
+ - lib/tidy_ffi/tidy_ffi_extensions.rb
40
+ - lib/tidy_ffi.rb
41
+ files:
42
+ - CHANGELOG
43
+ - LICENSE
44
+ - Manifest
45
+ - README.rdoc
46
+ - Rakefile
47
+ - lib/tidy_ffi/interface.rb
48
+ - lib/tidy_ffi/lib_tidy.rb
49
+ - lib/tidy_ffi/options_container.rb
50
+ - lib/tidy_ffi/tidy.rb
51
+ - lib/tidy_ffi/tidy_ffi_extensions.rb
52
+ - lib/tidy_ffi.rb
53
+ - test/test_helper.rb
54
+ - test/test_lowlevel.rb
55
+ - test/test_options.rb
56
+ - test/test_simple.rb
57
+ - tidy_ffi.gemspec
58
+ has_rdoc: false
59
+ homepage: http://github.com/libc/tidy_ffi
60
+ post_install_message:
61
+ rdoc_options:
62
+ - --line-numbers
63
+ - --inline-source
64
+ - --title
65
+ - Tidy_ffi
66
+ - --main
67
+ - README.rdoc
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "1.2"
81
+ version:
82
+ requirements: []
83
+
84
+ rubyforge_project: tidy-ffi
85
+ rubygems_version: 1.2.0
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Tidy library interface via FFI
89
+ test_files:
90
+ - test/test_helper.rb
91
+ - test/test_lowlevel.rb
92
+ - test/test_options.rb
93
+ - test/test_simple.rb