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



163
164
165
# File 'lib/tidy_ffi/interface.rb', line 163

def self.default_options
  @default_options ||= load_default_options
end

.load_default_optionsObject

Loads default options.



108
109
110
111
112
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
# File 'lib/tidy_ffi/interface.rb', line 108

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)


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/tidy_ffi/interface.rb', line 168

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



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/tidy_ffi/interface.rb', line 88

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