Class: TidyFFI::Interface

Inherits:
Object
  • Object
show all
Defined in:
lib/tidy_ffi/interface.rb

Overview

Low level interface to libtidy.

Constant Summary collapse

LibTidy =
TidyFFI::LibTidy

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(doc) ⇒ Interface

:nodoc:



14
15
16
# File 'lib/tidy_ffi/interface.rb', line 14

def initialize(doc) #:nodoc:
  @doc = doc
end

Class Method Details

.default_optionsObject

Returns a hash that represents default options for tidy. Key for hash is the option name, value is also a hash… Possible values are:

  • :type - either :string, :integer, :boolean or :enum

  • :readonly?

  • :default - default value of an option

  • :values - possible values for :enum

  • :name



168
169
170
# File 'lib/tidy_ffi/interface.rb', line 168

def self.default_options
  @default_options ||= load_default_options
end

.load_default_optionsObject

Loads default options.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/tidy_ffi/interface.rb', line 113

def load_default_options
  return if @default_options

  doc = LibTidy.tidyCreate
  iterator = LibTidy.tidyGetOptionList(doc)

  @default_options = {}

  FFI::MemoryPointer.new(:pointer, 1) do |pointer|
    pointer.put_pointer(0, iterator)

    until iterator.null?
      opt = LibTidy.tidyGetNextOption(doc, pointer)

      option = {}

      option[:name] = LibTidy.tidyOptGetName(opt).gsub('-', '_').intern
      option[:readonly?] = LibTidy.tidyOptIsReadOnly(opt) != 0
      option[:type] = LibTidy::TIDY_OPTION_TYPE[LibTidy.tidyOptGetType(opt)]
      option[:default] = case option[:type]
      when :string
        (LibTidy.tidyOptGetDefault(opt) rescue "")
      when :integer
        if pick_list = pick_list_for(opt)
          option[:type] = :enum
          option[:values] = pick_list
          pick_list[LibTidy.tidyOptGetDefaultInt(opt)]
        else
          LibTidy.tidyOptGetDefaultInt(opt)
        end
      when :boolean
        LibTidy.tidyOptGetDefaultBool(opt) != 0
      end

      @default_options[option[:name]] = option

      iterator = pointer.get_pointer(0)
    end

  end
  @default_options.freeze
ensure
  LibTidy.tidyRelease(doc)
end

.option_valid?(option, value) ⇒ Boolean

Returns true if value is valid for option and false otherwise.

Returns:

  • (Boolean)


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/tidy_ffi/interface.rb', line 173

def self.option_valid?(option, value)
  return false unless spec = default_options[option]
  
  case spec[:type]
  when :boolean
    true == value || false == value || value == 0 || value == 1 || %w(on off true false 0 1 yes no).include?(value.downcase)
  when :integer
    Integer === value || !!(value =~ /^\d+$/)
  when :enum
    if Integer === value
      !!spec[:values][value]
    else
      spec[:values].include?(value)
    end
  when :string
    String === value || Symbol === value
  end
end

.pick_list_for(opt) ⇒ Object

Returns enumeration for opt.

Some tidy options might try to trespass as integer, and in order to caught perpertraitors we need to call tidyOptGetPickList



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/tidy_ffi/interface.rb', line 93

def pick_list_for(opt)
  iterator = LibTidy.tidyOptGetPickList(opt)

  return nil if iterator.null?

  pick_list = []

  FFI::MemoryPointer.new(:pointer, 1) do |pointer|
    pointer.put_pointer(0, iterator)
    until iterator.null?
      pick_list << LibTidy.tidyOptGetNextPick(opt, pointer)
      iterator = pointer.get_pointer(0)
    end
  end

  pick_list
end

.with_docObject

Returns a TidyFFI::Interface with initialized interface.



6
7
8
9
10
11
12
# File 'lib/tidy_ffi/interface.rb', line 6

def self.with_doc
  doc = LibTidy.tidyCreate
  nd = new(doc)
  nd.with_redirected_error_buffer { yield nd }
ensure
  LibTidy.tidyRelease(doc)
end

Instance Method Details

#apply_options(options) ⇒ Object

Apply options



19
20
21
22
23
24
25
26
27
28
# File 'lib/tidy_ffi/interface.rb', line 19

def apply_options(options)
  options.each do |key, value|
    k = key.to_s.gsub('_', '-')

    option = LibTidy.tidyGetOptionByName(@doc, k)
    raise ArgumentError, "don't know about option #{key}" if option.null?
    id = LibTidy.tidyOptGetId(option)
    raise ArgumentError, "can't setup option #{key} to #{value}" if LibTidy.tidyOptSetValue(@doc, id, value.to_s) == 0
  end
end

#cleanObject Also known as: clean_and_repair, repair

Cleans string



36
37
38
39
# File 'lib/tidy_ffi/interface.rb', line 36

def clean
  @output = nil
  LibTidy.tidyCleanAndRepair(@doc)
end

#errorsObject



53
54
55
# File 'lib/tidy_ffi/interface.rb', line 53

def errors
  @error_buffer[:bp]
end

#outputObject

Returns output from tidy library



44
45
46
47
48
49
50
51
# File 'lib/tidy_ffi/interface.rb', line 44

def output
  @output ||= begin
    with_buffer_pointer do |buf|
      LibTidy.tidySaveBuffer(@doc, buf)
      buf[:bp]
    end
  end
end

#string=(str) ⇒ Object

Sets string to tidy



31
32
33
# File 'lib/tidy_ffi/interface.rb', line 31

def string=(str)
  LibTidy.tidyParseString(@doc, str)
end

#with_buffer_pointerObject

Yields block with new buffer



69
70
71
72
73
74
# File 'lib/tidy_ffi/interface.rb', line 69

def with_buffer_pointer
  buf = tidy_buf_object.new
  yield buf
ensure
  LibTidy.tidyBufFree(buf)
end

#with_redirected_error_bufferObject

Redirects error buffer



58
59
60
61
62
63
64
65
66
# File 'lib/tidy_ffi/interface.rb', line 58

def with_redirected_error_buffer
  with_buffer_pointer do |buf|
    @error_buffer = buf
    LibTidy.tidySetErrorBuffer(@doc, buf)
    yield
  end
ensure
  @error_buffer = nil
end