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:



16
17
18
# File 'lib/tidy_ffi/interface.rb', line 16

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



172
173
174
# File 'lib/tidy_ffi/interface.rb', line 172

def self.default_options
  @default_options ||= load_default_options
end

.load_default_optionsObject

Loads default options.



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
157
158
159
160
# File 'lib/tidy_ffi/interface.rb', line 117

def load_default_options
  return if @default_options

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

  @default_options = {}

  pointer = FFI::MemoryPointer.new(:pointer, 1)
  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

  @default_options.freeze
ensure
  pointer.free if pointer
  LibTidy.tidyRelease(doc)
end

.option_valid?(option, value) ⇒ Boolean

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

Returns:

  • (Boolean)


177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/tidy_ffi/interface.rb', line 177

def self.option_valid?(option, value)
  spec = default_options[option]
  return false unless spec

  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.downcase)
    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



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/tidy_ffi/interface.rb', line 96

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

  return nil if iterator.null?

  pick_list = []

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

  pick_list
ensure
  pointer.free if pointer
end

.with_docObject

Returns a TidyFFI::Interface with initialized interface.



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

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



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

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



38
39
40
41
# File 'lib/tidy_ffi/interface.rb', line 38

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

#errorsObject



55
56
57
# File 'lib/tidy_ffi/interface.rb', line 55

def errors
  @error_buffer[:bp]
end

#outputObject

Returns output from tidy library



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

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



33
34
35
# File 'lib/tidy_ffi/interface.rb', line 33

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

#with_buffer_pointerObject

Yields block with new buffer



71
72
73
74
75
76
77
# File 'lib/tidy_ffi/interface.rb', line 71

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

#with_redirected_error_bufferObject

Redirects error buffer



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

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