Class: Alexandria::SmartLibrary

Inherits:
Array
  • Object
show all
Extended by:
GetText
Includes:
Exportable, Logging, GetText
Defined in:
lib/alexandria/smart_library.rb,
lib/alexandria/export_library.rb

Defined Under Namespace

Classes: Rule

Constant Summary collapse

ALL_RULES =
1
ANY_RULE =
2
DIR =
File.join(ENV['HOME'], '.alexandria', '.smart_libraries')
EXT =
'.yaml'
@@deleted_libraries =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Exportable

#export_as_bibtex, #export_as_csv_list, #export_as_html, #export_as_ipod_notes, #export_as_isbn_list, #export_as_onix_xml_archive, #export_as_tellico_xml_archive

Methods included from Logging

included, #log

Constructor Details

#initialize(name, rules, predicate_operator_rule) ⇒ SmartLibrary

Returns a new instance of SmartLibrary.



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/alexandria/smart_library.rb', line 39

def initialize(name, rules, predicate_operator_rule)
  super()
  raise if name.nil? || rules.nil? || predicate_operator_rule.nil?
  @name = name.dup.force_encoding('UTF-8')
  @rules = rules
  @predicate_operator_rule = predicate_operator_rule
  libraries = Libraries.instance
  libraries.add_observer(self)
  self.libraries = libraries.all_regular_libraries
  # carry deleted books over from libraries that are part of the smart library
  self.deleted_books = libraries.deleted_books
  @cache = {}
end

Instance Attribute Details

#deleted_booksObject

Returns the value of attribute deleted_books.



34
35
36
# File 'lib/alexandria/smart_library.rb', line 34

def deleted_books
  @deleted_books
end

#n_ratedObject (readonly)

Returns the value of attribute n_rated.



218
219
220
# File 'lib/alexandria/smart_library.rb', line 218

def n_rated
  @n_rated
end

#nameObject

Returns the value of attribute name.



33
34
35
# File 'lib/alexandria/smart_library.rb', line 33

def name
  @name
end

#predicate_operator_ruleObject

Returns the value of attribute predicate_operator_rule.



34
35
36
# File 'lib/alexandria/smart_library.rb', line 34

def predicate_operator_rule
  @predicate_operator_rule
end

#rulesObject

Returns the value of attribute rules.



34
35
36
# File 'lib/alexandria/smart_library.rb', line 34

def rules
  @rules
end

Class Method Details

.deleted_librariesObject



230
231
232
# File 'lib/alexandria/smart_library.rb', line 230

def self.deleted_libraries
  @@deleted_libraries
end

.from_hash(hash) ⇒ Object



126
127
128
129
130
# File 'lib/alexandria/smart_library.rb', line 126

def self.from_hash(hash)
  SmartLibrary.new(hash[:name],
                   hash[:rules].map { |x| Rule.from_hash(x) },
                   hash[:predicate_operator_rule] == :all ? ALL_RULES : ANY_RULE)
end

.loadallObject



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/alexandria/smart_library.rb', line 53

def self.loadall
  a = []
  begin
    # Deserialize smart libraries.
    Dir.chdir(DIR) do
      Dir['*' + EXT].each do |filename|
        # Skip non-regular files.
        next unless File.stat(filename).file?

        text = IO.read(filename)
        hash = YAML.safe_load(text, whitelist_classes = [Symbol])
        begin
          smart_library = from_hash(hash)
          a << smart_library
        rescue => e
          puts "Cannot load serialized smart library: #{e}"
          puts e.backtrace
        end
      end
    end
  rescue Errno::ENOENT
    # First run and no smart libraries yet? Provide some default
    # ones.
    sample_smart_libraries.each do |smart_library|
      smart_library.save
      a << smart_library
    end
  end
  a.each(&:refilter)
  a
end

.really_delete_deleted_librariesObject



234
235
236
237
238
239
# File 'lib/alexandria/smart_library.rb', line 234

def self.really_delete_deleted_libraries
  @@deleted_libraries.each do |library|
    puts "Deleting smart library file (#{yaml})" if $DEBUG
    FileUtils.rm_rf(library.yaml)
  end
end

.sample_smart_librariesObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/alexandria/smart_library.rb', line 85

def self.sample_smart_libraries
  a = []

  operands = Rule::Operands::LEFT

  # Favorite books.
  rule = Rule.new(operands.find { |x| x.book_selector == :rating },
                  Rule::Operators::IS,
                  Book::MAX_RATING_STARS.to_s)
  a << new(_('Favorite'), [rule], ALL_RULES)

  # Loaned books.
  rule = Rule.new(operands.find { |x| x.book_selector == :loaned },
                  Rule::Operators::IS_TRUE,
                  nil)
  a << new(_('Loaned'), [rule], ALL_RULES)

  # Redd books.
  rule = Rule.new(operands.find { |x| x.book_selector == :redd },
                  Rule::Operators::IS_TRUE,
                  nil)
  a << new(_('Read'), [rule], ALL_RULES)

  # Own books.
  rule = Rule.new(operands.find { |x| x.book_selector == :own },
                  Rule::Operators::IS_TRUE,
                  nil)
  a << new(_('Owned'), [rule], ALL_RULES)

  # Want books.
  rule = Rule.new(operands.find { |x| x.book_selector == :want },
                  Rule::Operators::IS_TRUE,
                  nil)
  rule2 = Rule.new(operands.find { |x| x.book_selector == :own },
                   Rule::Operators::IS_NOT_TRUE,
                   nil)
  a << new(_('Wishlist'), [rule, rule2], ALL_RULES)

  a
end

Instance Method Details

#==(object) ⇒ Object



224
225
226
# File 'lib/alexandria/smart_library.rb', line 224

def ==(object)
  object.is_a?(self.class) && object.name == name
end

#copy_covers(somewhere) ⇒ Object



207
208
209
210
211
212
213
214
215
216
# File 'lib/alexandria/smart_library.rb', line 207

def copy_covers(somewhere)
  FileUtils.rm_rf(somewhere) if File.exist?(somewhere)
  FileUtils.mkdir(somewhere)
  each do |book|
    library = @cache[book]
    next unless File.exist?(library.cover(book))
    FileUtils.cp(File.join(library.path, book.ident + Library::EXT[:cover]),
                 File.join(somewhere, library.final_cover(book)))
  end
end

#cover(book) ⇒ Object



178
179
180
# File 'lib/alexandria/smart_library.rb', line 178

def cover(book)
  @cache[book].cover(book)
end

#deleteObject



241
242
243
244
245
246
247
248
249
250
251
# File 'lib/alexandria/smart_library.rb', line 241

def delete
  if @@deleted_libraries.include?(self)
    puts 'Already deleted a SmartLibrary with this name'
    puts '(this might mess up undeletes...)'
    FileUtils.rm_rf(yaml)
    # so we just delete the old smart library, and
    # 'pending' delete the new one of the same name...
    # urrr... yeah, that'll work!
  end
  @@deleted_libraries << self
end

#deleted?Boolean

Returns:

  • (Boolean)


253
254
255
# File 'lib/alexandria/smart_library.rb', line 253

def deleted?
  @@deleted_libraries.include?(self)
end

#final_cover(book) ⇒ Object



203
204
205
# File 'lib/alexandria/smart_library.rb', line 203

def final_cover(book)
  @cache[book].final_cover(book)
end

#n_unratedObject



220
221
222
# File 'lib/alexandria/smart_library.rb', line 220

def n_unrated
  length - n_rated
end

#refilterObject



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/alexandria/smart_library.rb', line 161

def refilter
  filters = @rules.map(&:filter_proc)
  selector = @predicate_operator_rule == ALL_RULES ? :all? : :any?

  clear
  @cache.clear

  @libraries.each do |library|
    filtered_library = library.select do |book|
      filters.send(selector) { |filter| filter.call(book) } # Problem here.
    end
    filtered_library.each { |x| @cache[x] = library }
    concat(filtered_library)
  end
  @n_rated = count { |x| !x.rating.nil? && x.rating > 0 }
end

#save(book = nil) ⇒ Object



190
191
192
193
194
195
196
197
# File 'lib/alexandria/smart_library.rb', line 190

def save(book = nil)
  if book
    @cache[book].save(book)
  else
    FileUtils.mkdir_p(DIR) unless File.exist? DIR
    File.open(yaml, 'w') { |io| io.puts to_hash.to_yaml }
  end
end

#save_cover(book, _cover_uri) ⇒ Object



199
200
201
# File 'lib/alexandria/smart_library.rb', line 199

def save_cover(book, _cover_uri)
  @cache[book].save_cover(book)
end

#to_hashObject



132
133
134
135
136
137
138
# File 'lib/alexandria/smart_library.rb', line 132

def to_hash
  {
    name: @name,
    predicate_operator_rule: @predicate_operator_rule == ALL_RULES ? :all : :any,
    rules: @rules.map(&:to_hash)
  }
end

#undeleteObject



257
258
259
260
# File 'lib/alexandria/smart_library.rb', line 257

def undelete
  raise unless @@deleted_libraries.include?(self)
  @@deleted_libraries.delete(self)
end

#update(*params) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
# File 'lib/alexandria/smart_library.rb', line 149

def update(*params)
  if params.first.is_a?(Libraries)
    libraries, _, library = params
    unless library.is_a?(self.class)
      self.libraries = libraries.all_libraries
      refilter
    end
  elsif params.first.is_a?(Library)
    refilter
  end
end

#yaml(book = nil) ⇒ Object



182
183
184
185
186
187
188
# File 'lib/alexandria/smart_library.rb', line 182

def yaml(book = nil)
  if book
    @cache[book].yaml(book)
  else
    File.join(DIR, @name + EXT)
  end
end