Module: ArchiveTree::Core

Defined in:
lib/archive_tree/core.rb

Overview

:nodoc:

Instance Method Summary collapse

Instance Method Details

#archive_node(options = {}) ⇒ Object

Named scope that retrieves the records for a given year and month.

Note: This scope can be chained, e.g. Post.archive_node.where('id > 100')

Default behaviors

  • :year #=> defaults to the current year (e.g. 2010)
  • :month #=> all

Example using default values:

Post.archive_node

Example overridding values:

Post.archive_node(:year => 2010, :month => 1)


18
19
20
21
22
23
24
# File 'lib/archive_tree/core.rb', line 18

def archive_node(options={})
  options.reverse_merge! ({ :year => Time.now.year })

  where("#{date_field} IS NOT NULL").
  where("EXTRACT(YEAR FROM #{date_field}) = :year", :year => options[:year]).
  where("EXTRACT(MONTH FROM #{date_field}) = :month OR :month IS NULL", :month => options[:month])
end

#archive_tree(options = {}) ⇒ Object

Constructs an archive tree in the form of a nested Hash.

Hash levels

  1. Years (integer)
  2. Months (integer)
  3. Your records (ActiveRecord::Relation)

Default behaviors to take note:

* All records are sweeped by default based on their +date_field+ column
* Years without records are not returned
* Months without records are not returned
* The keys are integers, thus they will likely require conversion

Options

  • :years => Array of years to sweep
  • :months => Array of months to sweep of each year
  • :years_and_months => Hash of years, each containing an Array of months to sweep
  • :month_names => Accepts one of two symbols :long and :short. Please note that this overrides the default value

Examples context Please note that for the sake of simplicity these examples assume that any given year has only one Post record for any given month and will be represented in the following format: { 2010 => => [post] }

Default usage:

Post.archive_tree #=> { 2010 => { 1 => [Post], 2 => [Post] },
                      2011 => { 1 => [Post], 4 => [Post], 8 => [Post] } }

Sweep all months of the current year:

Post.archive_tree(:years => [Time.now.year]) #=> { 2010 => { 1 => [Post], 2 => [Post] } }

Skip all months other than January (1):

Post.archive_tree(:months => [1]) #=> { 2010 => { 1 => [Post] },
                                    { 2011 => { 1 => [Post] } } }

Only sweep January 2010:

Post.archive_tree(:years_and_months => { 2010 => [1] }) #=> { 2010 => { 1 => [Post] } }

Considerations This method has poor performance due to the 'linear' way in which the queries are being constructed and executed.

TODO: Optimize the queries.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/archive_tree/core.rb', line 127

def archive_tree(options = {})
  tree = {}
  years = options[:years_and_months] ? options[:years_and_months].keys : nil || options[:years] ||
    archived_years.keys || []

  years.each do |year|
    tree[year] = {}
    months = archived_months(:year => year).keys

    if options[:years_and_months]
      months.reject! { |m| !options[:years_and_months][year].include?(m) }
    elsif options[:months]
      months.reject! { |m| !options[:months].include?(m) }
    end

    months.each do |month|
      tree[year][month] = {}
      tree[year][month] = archive_node(:year => year, :month => month)
    end
  end

  tree
end

#archived_months(options = {}) ⇒ Object

For a given year, constructs a single-level hash of months using the defined date_field column.

The returned hash is a key-value-pair representing the number of records for a given month, within a given years. This hash can have string or integer keys, depending on the value of :month_names option, which can be passed in the options hash.

Default behaviors

  • By default the months are returned in their integer representation (eg.: 1 represents January)
  • The current year is assumed to be the default scope of the query

Options

  • :year #=> Integer representing the year to sweep. Defaults to the current year.
  • :month_names #=> Null, or absent will result in months represented as integer (default). Also accepts :long and :short, depending on the desired lenght length for the month name.

Considerations Given the way the queries are currently constructed and executed this method suffers from poor performance.

TODO: Optimize the queries.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/archive_tree/core.rb', line 64

def archived_months(options = {})
  months  = {}
  month_format = options.delete(:month_names) || :int

  where("EXTRACT(YEAR FROM #{date_field}) = #{options[:year] || Time.now.year}").
  group("EXTRACT(MONTH FROM #{date_field})").size.each do |month, c|
    key = case month_format
    when :long
      Date::MONTHNAMES[month.to_i]
    when :short
      Date::ABBR_MONTHNAMES[month.to_i]
    else
      month.to_i
    end

    months[key] = c
  end

  months
end

#archived_yearsObject

Constructs a single-level hash of years using the defined date_field column.

The returned hash is a key-value-pair of integers. The key represents the year (in integer) and the value represents the number of records for that year (also in integer).

This method executes a SQL query of type COUNT, grouping the results by year.

Note: the query makes use of the YEAR sql command, which might not be supported by all RDBMs.

Exampe:

Post.years_hash #=> { 2009 => 8, 2010 => 30 }


37
38
39
40
41
42
43
# File 'lib/archive_tree/core.rb', line 37

def archived_years
  years = {}
  where("#{date_field} IS NOT NULL").
  group("EXTRACT(YEAR FROM #{date_field})").size.each { |year, count| years[year.to_i] = count }

  years
end