Class: Things2THL::Converter
- Inherits:
-
Object
- Object
- Things2THL::Converter
- Defined in:
- lib/Things2THL.rb
Instance Attribute Summary collapse
-
#created ⇒ Object
Returns the value of attribute created.
-
#options ⇒ Object
Returns the value of attribute options.
-
#things ⇒ Object
Returns the value of attribute things.
-
#thl ⇒ Object
Returns the value of attribute thl.
Instance Method Summary collapse
- #add_extra_node(prop, newnode) ⇒ Object
-
#add_list_notes(node, prop) ⇒ Object
Add a new task containing project notes when the project is a THL list, since THL lists cannot have notes.
-
#add_notes(node, prop) ⇒ Object
Transfer processed notes.
-
#add_project_duedate(node, prop) ⇒ Object
When projects are lists, if the project has a due date, we add a bogus task to it to represent its due date, since lists in THL cannot have due dates.
- #aliastostring(node) ⇒ Object
-
#archive_completed(prop) ⇒ Object
Archive completed/canceled if requested.
-
#check_today(node, prop) ⇒ Object
Check if node is in the Today list.
-
#container_for(node) ⇒ Object
Create if necessary and return an appropriate THL container object for the new node, according to the node’s class and options selected.
-
#convert_notes(notes) ⇒ Object
Process Things notes before adding them to THL.
-
#create_focuscaches ⇒ Object
Create the focus caches.
- #create_in_thl(node, parent) ⇒ Object
-
#find_or_create(props, parent = @thl.folders_group.get) ⇒ Object
Find or create a list or a folder inside the given parent (or the top-level folders group if not given).
-
#fix_completed_canceled(node, prop) ⇒ Object
Things sets both ‘completion_date’ and ‘cancellation_date’ for both completed and canceled tasks, which confuses THL, so we delete the one that should not be there.
-
#focus_of(node) ⇒ Object
Get the focuses in which a task is visible.
-
#get_cached_or_process(node) ⇒ Object
See if we have processed a node already - in that case return the cached THL node.
-
#get_focusnames(all = false) ⇒ Object
Get all the focus names.
- #hextostring(hexstr) ⇒ Object
-
#in_focus?(focus, node) ⇒ Boolean
Check if a node is in a certain focus Node can be a ThingsNode, and AS node, or a node ID.
-
#initialize(opt_struct = nil, things_location = nil, thl_location = nil) ⇒ Converter
constructor
A new instance of Converter.
- #loose_tasks_name(parent) ⇒ Object
- #new_folder(name, parent = @thl.folders_group.get) ⇒ Object
-
#process(node) ⇒ Object
Process a single node.
-
#process_tags(node, prop, inherit_project_tags, inherit_area_tags) ⇒ Object
Process tags.
- #props_from_node(node) ⇒ Object
-
#simple_find_or_create(what, name, parent = @thl.folders_group.get) ⇒ Object
Simplified version of find_or_create which simply takes :new and :name.
-
#thl_node_name(node) ⇒ Object
Get the name/title for a THL node.
-
#thl_node_type(node) ⇒ Object
Get the type of the THL node that corresponds to the given Things node, depending on the options specified.
-
#top_level_for_focus(focusnames) ⇒ Object
Create (if necessary) and return an appropriate THL container for a given top-level Things focus.
-
#top_level_for_node(node) ⇒ Object
Get the top-level focus for a node.
-
#top_level_node ⇒ Object
Return the provided top level node, or the folders group if the option is not specified.
Constructor Details
#initialize(opt_struct = nil, things_location = nil, thl_location = nil) ⇒ Converter
Returns a new instance of Converter.
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/Things2THL.rb', line 268 def initialize(opt_struct = nil, things_location = nil, thl_location = nil) @options=opt_struct || Things2THL. thingsappname=things_location || 'Things' thlappname=thl_location || 'The Hit List' begin @things = Appscript.app(thingsappname) @thl = Appscript.app(thlappname) rescue ApplicationNotFoundError => e puts "I could not open one of the needed applications: #{e.}" exit(1) end # Regular expression to match context tags. Compile it here to avoid # repetition later on. . = Regexp.compile(.) if . # Regular expression to match time-estimate tags. Compile it here to avoid # repetition later on. . = Regexp.compile(.) if . # Structure to keep track of already create items # These hashes are indexed by Things node ID (node.id_). Each element # contains a hash with two elements: # :things_node - pointer to the corresponding AS node in Things # :thl_node - pointer to the corresponding AS node in THL @cache_nodes = {} # Cache of which items are contained in each focus (Inbox, etc.) # Indexed by focus name, value is a hash with elements keyed by the # id_ of each node that belongs to that focus. Existence of the key # indicates existence in the focus. @cache_focus = {} # Statistics @created = { :task => 0, :list => 0, :folder => 0 } end |
Instance Attribute Details
#created ⇒ Object
Returns the value of attribute created.
266 267 268 |
# File 'lib/Things2THL.rb', line 266 def created @created end |
#options ⇒ Object
Returns the value of attribute options.
266 267 268 |
# File 'lib/Things2THL.rb', line 266 def @options end |
#things ⇒ Object
Returns the value of attribute things.
266 267 268 |
# File 'lib/Things2THL.rb', line 266 def things @things end |
#thl ⇒ Object
Returns the value of attribute thl.
266 267 268 |
# File 'lib/Things2THL.rb', line 266 def thl @thl end |
Instance Method Details
#add_extra_node(prop, newnode) ⇒ Object
825 826 827 828 |
# File 'lib/Things2THL.rb', line 825 def add_extra_node(prop, newnode) prop[:__newnodes__] = [] unless prop.has_key?(:__newnodes__) prop[:__newnodes__].push(newnode) end |
#add_list_notes(node, prop) ⇒ Object
Add a new task containing project notes when the project is a THL list, since THL lists cannot have notes
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 |
# File 'lib/Things2THL.rb', line 858 def add_list_notes(node, prop) new_node_type = thl_node_type(node) # Process notes only for non-areas if (node.type != :area) # If the node has notes but the THL node is a list, add the notes as a task in there # If the node has notes but the THL node is a folder (this shouldn't happen), print a warning if node.notes? && new_node_type == :list newnode = { :new => :task, :with_properties => { :title => "Notes for '#{prop[:name]}'", :notes => convert_notes(node.notes) }} # Mark as completed if the project is completed if node.status == :completed || node.status == :canceled newnode[:with_properties][:completed] = true archive_completed(newnode[:with_properties]) end add_extra_node(prop, newnode) end if node.notes? && new_node_type == :folder $stderr.puts "Error: cannot transfer notes into new folder: #{node.notes}" end end end |
#add_notes(node, prop) ⇒ Object
Transfer processed notes
882 883 884 |
# File 'lib/Things2THL.rb', line 882 def add_notes(node, prop) prop[:notes] = convert_notes(node.notes) if node.notes? end |
#add_project_duedate(node, prop) ⇒ Object
When projects are lists, if the project has a due date, we add a bogus task to it to represent its due date, since lists in THL cannot have due dates.
888 889 890 891 892 893 894 895 896 897 898 |
# File 'lib/Things2THL.rb', line 888 def add_project_duedate(node, prop) new_node_type = thl_node_type(node) return unless node.type == :project && new_node_type == :list && node.due_date? # Create the new node newnode = { :new => :task, :with_properties => { :title => "Due date for '#{prop[:name]}'", :due_date => node.due_date } } add_extra_node(prop, newnode) end |
#aliastostring(node) ⇒ Object
834 835 836 |
# File 'lib/Things2THL.rb', line 834 def aliastostring(node) hextostring((node/'alias').inner_text) end |
#archive_completed(prop) ⇒ Object
Archive completed/canceled if requested
733 734 735 |
# File 'lib/Things2THL.rb', line 733 def archive_completed(prop) prop[:archived] = true if .archivecompleted && (prop[:completed] || prop[:canceled]) end |
#check_today(node, prop) ⇒ Object
Check if node is in the Today list
819 820 821 822 823 |
# File 'lib/Things2THL.rb', line 819 def check_today(node, prop) if in_focus?('Today', node) prop[:start_date] = Time.parse('today at 00:00') end end |
#container_for(node) ⇒ Object
Create if necessary and return an appropriate THL container object for the new node, according to the node’s class and options selected. A task in THL can only be contained in a list or in another task. So if parent is a folder and note is a task, we need to find or create an auxiliary list to contain it.
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
# File 'lib/Things2THL.rb', line 559 def container_for(node) # If its top-level container is nil, it means we need to skip this node tlcontainer=top_level_for_node(node) return nil unless tlcontainer # Otherwise, run through the process container = case node.type when :area tlcontainer when :project if .areas && !.areas_as && (.structure != :projects_areas_as_lists) && node.area? get_cached_or_process(node.area) else tlcontainer end when :selected_to_do if node.project? get_cached_or_process(node.project) elsif node.area? && .areas && !.areas_as get_cached_or_process(node.area) else # It's a loose task tlcontainer end else raise "Invalid Things node type: #{node.type}" end # Now we check the container type. Tasks can only be contained in lists, # so if the container is a folder, we have to create a list to hold the task if container && (container.class_.get == :folder) && (thl_node_type(node) == :task) if node.type == :project simple_find_or_create(:list, .projectsfolder || 'Projects', container) else simple_find_or_create(:list, loose_tasks_name(container), container) end else container end end |
#convert_notes(notes) ⇒ Object
Process Things notes before adding them to THL.
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 |
# File 'lib/Things2THL.rb', line 839 def convert_notes(notes) return unless notes # First, parse the notes as XML and extract the contents of the <note> tag note_html = (Hpricot.XML(notes)/'/note').inner_html # Then parse the HTML html = Hpricot(note_html) # Then swap any <alias> tags with their unencoded content # TODO: this is a hack - it would be much better to understand the binary structure of the <alias> tag. while html.at('alias') html.at('alias').swap( aliastostring(html).gsub(/^.*\000\022\000.(.*?)\000.*$/m, 'file:///\1') ) end # Produce the HTML in "plain text" format, which shows the links in brackets result=html.to_plain_text # Eliminate double URIs of the form 'URI [URI]' (i.e. when the link text is the URI itself) result.gsub(/([\w]+:.*)\s+\[\1\]/, '\1') end |
#create_focuscaches ⇒ Object
Create the focus caches
668 669 670 671 672 673 674 675 676 677 678 |
# File 'lib/Things2THL.rb', line 668 def create_focuscaches get_focusnames.each { |focus| puts "Creating focus cache for #{focus}..." if $DEBUG @cache_focus[focus] = {} next if focus == "Logbook" && !.completed things.lists[focus].to_dos.get.each { |t| @cache_focus[focus][t.id_.get] = true } puts " Cache: #{@cache_focus[focus].inspect}" if $DEBUG } end |
#create_in_thl(node, parent) ⇒ Object
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 |
# File 'lib/Things2THL.rb', line 600 def create_in_thl(node, parent) if (parent) new_node_type = thl_node_type(node) new_node_props = props_from_node(node) additional_nodes = new_node_props.delete(:__newnodes__) new_node_spec = { :new => new_node_type, :with_properties => new_node_props } if .sync result=find_or_create(new_node_spec, parent) else @created[new_node_type]+=1 result=parent.end.make(new_node_spec) end if node.type == :area || node.type == :project @cache_nodes[node.id_]={} @cache_nodes[node.id_][:things_node] = node @cache_nodes[node.id_][:thl_node] = result end # Add new nodes if additional_nodes additional_nodes.each do |n| if .sync find_or_create(n, result) else @created[n[:new]]+=1 result.end.make(n) end end end return result else parent end end |
#find_or_create(props, parent = @thl.folders_group.get) ⇒ Object
Find or create a list or a folder inside the given parent (or the top-level folders group if not given)
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
# File 'lib/Things2THL.rb', line 377 def find_or_create(props, parent = @thl.folders_group.get) puts "find_or_create: props = #{props.inspect}" if $DEBUG what=props[:new] name=(what==:task) ? props[:with_properties][:title] : props[:with_properties][:name] parentclass=parent.class_.get unless what == :list || what == :folder || what == :task raise "find_or_create: 'props[:new]' parameter has to be :list, :folder or :task" end puts "parent of #{name} = #{parent}" if $DEBUG if (what == :folder || what == :list) && parentclass != :folder raise "find_or_create: parent is not a folder, it's a #{parentclass}" elsif what == :task && parentclass != :list && parentclass != :task raise "find_or_create: parent is not a list, it's a #{parentclass}" else if what == :task query = parent.tasks[its.title.eq(name)] if ! query.get.empty? query.get[0] else @created[what]+=1 parent.end.make(props) end else query = parent.groups[name] if query.exists query.get else @created[what]+=1 parent.end.make(props) end end end end |
#fix_completed_canceled(node, prop) ⇒ Object
Things sets both ‘completion_date’ and ‘cancellation_date’ for both completed and canceled tasks, which confuses THL, so we delete the one that should not be there.
720 721 722 723 724 725 726 727 728 729 730 |
# File 'lib/Things2THL.rb', line 720 def fix_completed_canceled(node,prop) if prop[:completed_date] && prop[:canceled_date] if prop[:canceled] prop.delete(:completed) prop.delete(:completed_date) else prop.delete(:canceled) prop.delete(:canceled_date) end end end |
#focus_of(node) ⇒ Object
Get the focuses in which a task is visible
681 682 683 684 685 686 687 688 689 690 691 692 |
# File 'lib/Things2THL.rb', line 681 def focus_of(node) result=[] get_focusnames.each { |focus| if in_focus?(focus, node) result.push(focus) end } if node.type == :area && node.suspended result.push('Someday') end result end |
#get_cached_or_process(node) ⇒ Object
See if we have processed a node already - in that case return the cached THL node. Otherwise, invoke the process() function on it, which will put it in the cache.
544 545 546 547 548 549 550 551 552 |
# File 'lib/Things2THL.rb', line 544 def get_cached_or_process(node) node_id=node.id_ if @cache_nodes.has_key?(node_id) @cache_nodes[node_id][:thl_node] else # If we don't have the corresponding node cached yet, do it now process(node) end end |
#get_focusnames(all = false) ⇒ Object
Get all the focus names
662 663 664 665 |
# File 'lib/Things2THL.rb', line 662 def get_focusnames(all=false) # Get only top-level items of type :list (areas are also there, but with type :area) unless all==true @cached_focusnames||=things.lists.get.select {|l| all || l.class_.get == :list }.map { |focus| focus.name.get } end |
#hextostring(hexstr) ⇒ Object
830 831 832 |
# File 'lib/Things2THL.rb', line 830 def hextostring(hexstr) [hexstr.delete(" ")].pack("H*") end |
#in_focus?(focus, node) ⇒ Boolean
Check if a node is in a certain focus Node can be a ThingsNode, and AS node, or a node ID
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
# File 'lib/Things2THL.rb', line 696 def in_focus?(focus, node) unless @cache_focus[focus] create_focuscaches end case node when ThingsNode key = node.id_ when Appscript::Reference key = node.id_.get when String key = node else puts "Unknown node object type: #{node.class}" return nil end return @cache_focus[focus].has_key?(key) end |
#loose_tasks_name(parent) ⇒ Object
363 364 365 366 367 368 369 |
# File 'lib/Things2THL.rb', line 363 def loose_tasks_name(parent) if parent == top_level_node "Loose tasks" else thl_node_name(parent) + " - loose tasks" end end |
#new_folder(name, parent = @thl.folders_group.get) ⇒ Object
411 412 413 414 415 |
# File 'lib/Things2THL.rb', line 411 def new_folder(name, parent = @thl.folders_group.get) @created[:folder]+=1 parent.end.make(:new => :folder, :with_properties => { :name => name }) end |
#process(node) ⇒ Object
Process a single node. Returns the new THL node.
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 |
# File 'lib/Things2THL.rb', line 637 def process(node) return unless node # Skip if we have already processed it return if @cache_nodes.has_key?(node.id_) # Areas don't have status, so we skip the check unless node.type == :area return if ( node.status == :completed || node.status == :canceled ) && !(.completed) end container=container_for(node) puts "Container for #{node.name}: #{container}" if $DEBUG unless container puts "Skipping trashed task '#{node.name}'" unless .quiet.nonzero? return end unless (.quiet.nonzero?) bullet = (node.type == :area) ? "*" : ((node.status == :completed) ? "✓" : (node.status == :canceled) ? "×" : "-") puts bullet + " " + node.name end newnode=create_in_thl(node, container) end |
#process_tags(node, prop, inherit_project_tags, inherit_area_tags) ⇒ Object
Process tags
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 |
# File 'lib/Things2THL.rb', line 738 def (node, prop, , ) = node..map {|t| t.name } taskcontexts = [] if # Merge project and area tags if node.project? |= node.project..map {|t| t.name } if .areas && node.project.area? |= node.project.area..map {|t| t.name } if .areas_as case .areas_as when :tags .push(node.project.area.name) when :contexts taskcontexts.push(node.project.area.name) end end end end end if .areas && node.area? && |= node.area..map {|t| t.name } if .areas_as case .areas_as when :tags .push(node.area.name) when :contexts taskcontexts.push(node.area.name) end end end unless .empty? # First process time-estimate tags if needed if . # Valid time tags will be deleted from the tags list =.delete_if do |t| if data=..match(t) timeestimate = nil # If the regex includes only one group, it is assumed to be # the time in minutes. If it includes two groups, the second # group specifies the time unit, as defined in Constants::TIMEUNITS case data.size when 0 puts "Invalid time tags regex, does not return any groups: #{..to_s}" when 1 # Assumed to be in minutes, timeestimate is in seconds timeestimate = data[1].to_i * 60 else # Second one is the units - the rest are ignored timeunit=Constants::TIMEUNITS[data[2]] if !timeunit puts "Invalid time estimate tag, I could not match the time unit: '#{t}'" else timeestimate = data[1].to_i * timeunit end end if timeestimate prop[:estimated_time] = timeestimate end end end end prop[:title] = [prop[:title], .map do |t| if . && ..match(t) # Contexts cannot have spaces, we also remove any initial @'s before adding our own. "@" + t.gsub(/^@+/, "").gsub(/ /, '_') else "/" + t + (t.index(" ")?"/":"") end end].join(' ') end unless taskcontexts.empty? prop[:title] = [prop[:title], taskcontexts.map do |c| # Contexts cannot have spaces, we also remove any initial @'s before adding our own. "@" + c.gsub(/^@+/, "").gsub(/ /, '_') end].join(' ') end end |
#props_from_node(node) ⇒ Object
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/Things2THL.rb', line 325 def props_from_node(node) newprops={} # Process the properties, according to how the mapping is specified in STRUCTURES pm=Constants::STRUCTURES[.structure][node.type][1] proptoset=nil pm.keys.each do |k| case pm[k] when Symbol proptoset=pm[k] value=node.node.properties_.get[k] newprops[proptoset] = value if value && value != :missing_value when Array proptoset=pm[k][0] value=pm[k][1][node.node.properties_.get[k]] newprops[proptoset] = value if value && value != :missing_value when Hash value = node.node.properties_.get[k] if value && value != :missing_value proptoset = pm[k][value] if proptoset newprops[proptoset] = true end end else puts "Invalid class for pm[k]=#{pm[k]} (#{pm[k].class})" end puts "Mapping node.#{k} (#{node.node.properties_.get[k]}) to newprops[#{proptoset}]=#{newprops[proptoset]}" if $DEBUG end # Do any necesary postprocessing postproc=Constants::STRUCTURES[.structure][node.type][2] if postproc puts "Calling post-processor #{postproc.to_s} with newprops=#{newprops.inspect}" if $DEBUG postproc.call(node, newprops, self) puts "After post-processor: #{newprops.inspect}" if $DEBUG end return newprops end |
#simple_find_or_create(what, name, parent = @thl.folders_group.get) ⇒ Object
Simplified version of find_or_create which simply takes :new and :name
372 373 374 |
# File 'lib/Things2THL.rb', line 372 def simple_find_or_create(what, name, parent = @thl.folders_group.get) find_or_create({:new => what, :with_properties => { :name => name } }, parent) end |
#thl_node_name(node) ⇒ Object
Get the name/title for a THL node.
321 322 323 |
# File 'lib/Things2THL.rb', line 321 def thl_node_name(node) node.properties_.get[Constants::TITLEPROP[node.class_.get]] end |
#thl_node_type(node) ⇒ Object
Get the type of the THL node that corresponds to the given Things node, depending on the options specified
310 311 312 313 314 315 316 317 318 |
# File 'lib/Things2THL.rb', line 310 def thl_node_type(node) case node when Symbol type=node else type=node.type end Constants::STRUCTURES[.structure][type][0] end |
#top_level_for_focus(focusnames) ⇒ Object
Create (if necessary) and return an appropriate THL container for a given top-level Things focus. If –top-level-folder is specified, all of them are simply folders inside that folder. Otherwise:
Inbox => Inbox
Next => default top level node
Scheduled, Someday => correspondingly-named top-level folders
Logbook => 'Completed' top-level folder
Projects => 'Projects' list if --projects-as-tasks
=> 'Projects' folder if --projects-folder was specified
=> default top level node otherwise
Trash => ignore
Today => ignore
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 |
# File 'lib/Things2THL.rb', line 446 def top_level_for_focus(focusnames) # We loop through all the focus names given, and return the first # one that produces a non-nil container focusnames.each do |focusname| result = if .toplevel case focusname when 'Trash', 'Today' nil when 'Inbox', 'Next' simple_find_or_create(:list, focusname, top_level_node) when 'Scheduled', 'Logbook' simple_find_or_create((thl_node_type(:project) == :task) ? :list : :folder, focusname, top_level_node) when 'Someday' simple_find_or_create(:folder, focusname, top_level_node) when 'Projects' if thl_node_type(:project) == :task simple_find_or_create(:list, .projectsfolder || 'Projects', top_level_node) else if .projectsfolder simple_find_or_create(:folder, .projectsfolder, top_level_node) else top_level_node end end else puts "Invalid focus name: #{focusname}" top_level_node end else # That was easy. Now for the more complicated part. case focusname when 'Inbox' thl.inbox.get when 'Next' top_level_node when 'Scheduled', 'Logbook' simple_find_or_create((thl_node_type(:project) == :task) ? :list : :folder, focusname, top_level_node) when 'Someday' simple_find_or_create(:folder, focusname, top_level_node) when 'Projects' if thl_node_type(:project) == :task simple_find_or_create(:list, .projectsfolder || 'Projects', top_level_node) else if .projectsfolder simple_find_or_create(:folder, .projectsfolder, top_level_node) else top_level_node end end when 'Trash', 'Today' nil else puts "Invalid focus name: #{focusname}" top_level_node end end return result if result end nil end |
#top_level_for_node(node) ⇒ Object
Get the top-level focus for a node. If it’s not directly contained in a focus, check its project and area, if any.
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
# File 'lib/Things2THL.rb', line 509 def top_level_for_node(node) # Areas are always contained at the top level, unless they # are suspended if node.type == :area if node.suspended return top_level_for_focus('Someday') else if .areasfolder return simple_find_or_create(:folder, .areasfolder || 'Areas', top_level_node) else return top_level_node end end end # Else, find if the node is contained in a top-level focus... foci=focus_of(node) # ...if not, look at its project and area if foci.empty? if node.project? tl=top_level_for_node(node.project) if !tl && node.area? && !.areas_as tl=top_level_for_node(node.area) end elsif node.area? && !.areas_as tl=top_level_for_node(node.area) end return tl end top_level_for_focus(foci) end |
#top_level_node ⇒ Object
Return the provided top level node, or the folders group if the option is not specified
418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/Things2THL.rb', line 418 def top_level_node return @thl.folders_group.get unless .toplevel unless @top_level_node # Create the top-level node if we don't have it cached yet if .sync @top_level_node=simple_find_or_create(:folder, .toplevel) else @top_level_node=new_folder(.toplevel) end end @top_level_node end |