cc2html 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ 1.9.3-p392
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cc2html (0.1.0)
4
+ cc2html (0.0.2)
5
5
  builder
6
6
  happymapper
7
7
  nokogiri
@@ -39,9 +39,9 @@ GEM
39
39
  rb-inotify (>= 0.9)
40
40
  lumberjack (1.0.4)
41
41
  method_source (0.8.2)
42
- mini_portile (0.5.2)
42
+ mini_portile (0.5.3)
43
43
  minitest (5.0.8)
44
- nokogiri (1.6.0)
44
+ nokogiri (1.6.1)
45
45
  mini_portile (~> 0.5.0)
46
46
  pry (0.9.12.2)
47
47
  coderay (~> 1.0.5)
@@ -51,8 +51,8 @@ GEM
51
51
  rb-fsevent (0.9.3)
52
52
  rb-inotify (0.9.2)
53
53
  ffi (>= 0.5.0)
54
- rdiscount (2.1.7)
55
- rubyzip (1.1.0)
54
+ rdiscount (2.1.7.1)
55
+ rubyzip (1.1.3)
56
56
  slop (3.4.6)
57
57
  thor (0.18.1)
58
58
  timers (1.1.0)
data/README.md CHANGED
@@ -15,22 +15,27 @@ Once RubyGems is installed you can install this gem:
15
15
 
16
16
  $ gem install cc2html
17
17
 
18
- Convert a Common Cartridge into HTML
18
+ Convert a Common Cartridge into EPUB
19
19
 
20
- $ cc2html migrate <path-to-cc-backup> <path-to-html-export-directory>
20
+ $ cc2html convert --format=epub <path-to-cc-backup> <name-of-epub-without-extension>
21
21
 
22
- Or into an epub
22
+ Or into HTML (mostly broken) :)
23
23
 
24
- $ cc2html migrate <path-to-cc-backup> <path-to-epub-export-directory> --format=epub
25
- # then zip of the contents of the folder into a .epub
24
+ $ cc2html convert <path-to-cc-backup> <path-to-html-export-directory>
26
25
 
27
26
  ## Todo
28
27
 
29
- * Oh so much!
30
- * Support converting all Common Cartridge versions
31
- * Create chapters from organization sections
32
- * Quiz conversion
33
- * make epub zip automatically
28
+ - [ ] Oh so much!
29
+ - [ ] Support converting all Common Cartridge versions
30
+ - [x] Create chapters from organization sections
31
+ - [ ] Quiz conversion
32
+ - [ ] Styles so it looks good
33
+ - [ ] Configurable styles
34
+ - [ ] Write epub/html output tests
35
+ - [ ] Make HTML output work
36
+ - [ ] Make HTML/EPUB code more DRY
37
+ - [ ] Handle CC weblink/topic/assignment/LTI types better
38
+ - [x] Automatically zip up epub
34
39
 
35
40
  ## Contributing
36
41
 
@@ -1,9 +1,10 @@
1
1
  module CC2HTML
2
2
  class Builder
3
- def initialize(manifest, dest_dir)
4
- @dest_dir = dest_dir
3
+ def initialize(manifest, dest_name)
4
+ @dest_name = dest_name
5
5
  @manifest = manifest
6
- @items = manifest.organizations.organization.item.items
6
+ @root_items = manifest.organizations.organization.item.items
7
+ @resources = manifest.resources.resources
7
8
  lom = manifest.metadata.lom
8
9
  @title = lom.general.title.title
9
10
  @description = lom.general.description.description if lom.general.description
@@ -2,14 +2,16 @@ require 'thor'
2
2
 
3
3
  module CC2HTML
4
4
  class CLI < Thor
5
- desc "migrate COMMON_CARTRIDGE_ZIP EXPORT_DIR", "Migrates Common Cartridge ZIP to an HTML representation"
5
+ desc "convert --format epub COMMON_CARTRIDGE_ZIP EXPORT_NAME", "Migrates Common Cartridge ZIP to an HTML or EPUB representation"
6
6
  method_option :format, :default => 'html'
7
7
  method_options :format => :string
8
+ method_option :leave_unzipped, :default => false
9
+ method_options :leave_unzipped => :boolean
8
10
 
9
- def migrate(source, destination)
11
+ def convert(source, destination)
10
12
  converter = CC2HTML::Converter.new source, destination, options
11
13
  converter.convert
12
- puts "#{source} converted to #{converter.cc_file_path}"
14
+ puts "#{source} converted to #{destination}.epub"
13
15
  end
14
16
  end
15
17
  end
@@ -2,18 +2,18 @@ module CC2HTML
2
2
  class Converter
3
3
  attr_reader :cc_file_path, :dest_dir
4
4
 
5
- def initialize(cc_file_path, dest_dir, options={})
5
+ def initialize(cc_file_path, dest_name, options={})
6
6
  @cc_file_path = cc_file_path
7
- @dest_dir = dest_dir
7
+ @dest_name = dest_name
8
8
  @settings = options
9
9
  end
10
10
 
11
11
  def convert
12
12
  manifest = IMS::CC::Manifest.read(@cc_file_path)
13
13
  if @settings[:format] == 'html'
14
- CC2HTML::HtmlBuilder.new(manifest, @dest_dir, @cc_file_path).generate
14
+ CC2HTML::HtmlBuilder.new(manifest, @dest_name, @cc_file_path).generate
15
15
  elsif @settings[:format] == 'epub'
16
- CC2HTML::EpubBuilder.new(manifest, @dest_dir, @cc_file_path).generate
16
+ CC2HTML::EpubBuilder.new(manifest, @dest_name, @cc_file_path, @settings).generate
17
17
  end
18
18
  end
19
19
 
@@ -2,34 +2,51 @@ module CC2HTML
2
2
  class EpubBuilder < Builder
3
3
  TEMPLATE_DIR = '../templates/epub/'
4
4
 
5
- def initialize(manifest, dest_dir, zip_file=nil)
6
- super(manifest, dest_dir)
5
+ def initialize(manifest, dest_name, zip_file, opts={})
6
+ super(manifest, dest_name)
7
7
  @file_name = 'cc_book'
8
- @content_dir = File.join(@dest_dir, 'content')
8
+ @content_dir = File.join(@dest_name, 'content')
9
9
  @zip_file = zip_file
10
- @items_with_resource = @items.select{|i|i.resource}
10
+ @items_with_resource = @manifest.organizations.organization.item.all_items.select{|i|i.resource}
11
+ @leave_in_folder = opts["leave_unzipped"]
11
12
  end
12
13
 
13
14
  def generate
14
- FileUtils.mkdir_p(@dest_dir)
15
+ FileUtils.mkdir_p(@dest_name)
15
16
  create_mimetype_file
16
17
  create_meta_inf
17
18
  FileUtils.mkdir_p(@content_dir)
18
19
  create_opf
19
20
  create_nav
20
21
  create_chapters
21
- copy_html_webresources
22
+ copy_images
23
+ copy_referenced_html_webresources
24
+ compress_into_epub
25
+ end
26
+
27
+ def compress_into_epub
28
+ unless @leave_in_folder
29
+ epub = @dest_name + '.epub'
30
+ FileUtils.rm(epub) if File.exists?(epub)
31
+ Zip::File.open(epub, Zip::File::CREATE) do |zipfile|
32
+ Dir["#{@dest_name}/**/**"].each do |file|
33
+ file_path = file.sub(@dest_name+'/', '')
34
+ zipfile.add(file_path, file)
35
+ end
36
+ end
37
+ FileUtils.rmtree(@dest_name)
38
+ end
22
39
  end
23
40
 
24
41
  def create_mimetype_file
25
- File.open(File.join(@dest_dir, 'mimetype'), 'w') do |f|
42
+ File.open(File.join(@dest_name, 'mimetype'), 'w') do |f|
26
43
  f << "application/epub+zip\n"
27
44
  end
28
45
  end
29
46
 
30
47
  def create_nav
31
48
  template = File.expand_path(TEMPLATE_DIR + 'navigation.html.erb', __FILE__)
32
- path = File.join(@content_dir = File.join(@dest_dir, 'content'), 'navigation.html')
49
+ path = File.join(@content_dir, 'navigation.html')
33
50
 
34
51
  File.open(path, 'w') do |file|
35
52
  erb = ERB.new(File.read(template))
@@ -43,7 +60,7 @@ module CC2HTML
43
60
  next if item.resource.type == 'webcontent'
44
61
  # so stupid... I'll fix later. :)
45
62
  @item = item
46
- path = File.join(@content_dir = File.join(@dest_dir, 'content'), item.identifierref + '.html')
63
+ path = File.join(@content_dir, item.identifierref + '.html')
47
64
  File.open(path, 'w') do |file|
48
65
  erb = ERB.new(File.read(template))
49
66
  file.write(erb.result(binding))
@@ -51,15 +68,34 @@ module CC2HTML
51
68
  end
52
69
  end
53
70
 
54
- def copy_html_webresources
71
+ def copy_referenced_html_webresources
55
72
  return unless @zip_file.end_with?('zip') || @zip_file.end_with?('imscc')
56
73
  Zip::File.open(@zip_file) do |zipfile|
57
74
  @items_with_resource.each do |item|
58
75
  if item.resource.type == 'webcontent' && item.resource.href && item.resource.href.end_with?('html')
59
- puts item.identifier
60
- path = File.join(@content_dir = File.join(@dest_dir, 'content'), item.identifierref + '.html')
76
+ path = File.join(@content_dir = File.join(@dest_name, 'content'), item.identifierref + '.html')
61
77
  File.open(path, 'w') do |file|
62
78
  entry = zipfile.get_entry(item.resource.href)
79
+ val = entry.get_input_stream.read
80
+ file << val.gsub('%24IMS_CC_FILEBASE%24', 'web_resources')
81
+ # file << entry.get_input_stream.read
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def copy_images
89
+ return unless @zip_file.end_with?('zip') || @zip_file.end_with?('imscc')
90
+ Zip::File.open(@zip_file) do |zipfile|
91
+ @resources.each do |resource|
92
+ if resource.type == 'webcontent' && resource.href &&
93
+ resource.href.start_with?('web_resources') &&
94
+ File.extname(resource.href) =~ /gif|jpg|png/i
95
+ path = File.join(@content_dir, resource.href)
96
+ FileUtils.mkdir_p(File.dirname(path))
97
+ File.open(path, 'w') do |file|
98
+ entry = zipfile.get_entry(resource.href)
63
99
  file << entry.get_input_stream.read
64
100
  end
65
101
  end
@@ -68,7 +104,7 @@ module CC2HTML
68
104
  end
69
105
 
70
106
  def create_meta_inf
71
- meta_dir = File.join(@dest_dir, 'META-INF')
107
+ meta_dir = File.join(@dest_name, 'META-INF')
72
108
  FileUtils.mkdir_p(meta_dir)
73
109
  File.open(File.join(meta_dir, 'container.xml'), 'w') do |f|
74
110
  f << <<-XML
@@ -84,7 +120,7 @@ XML
84
120
 
85
121
  def create_opf
86
122
  template = File.expand_path(TEMPLATE_DIR + 'descriptor.opf.erb', __FILE__)
87
- path = File.join(@content_dir = File.join(@dest_dir, 'content'), @file_name + '.opf')
123
+ path = File.join(@content_dir, @file_name + '.opf')
88
124
 
89
125
  File.open(path, 'w') do |file|
90
126
  erb = ERB.new(File.read(template))
@@ -3,14 +3,14 @@ module CC2HTML
3
3
  TEMPLATE_DIR = '../templates/html/'
4
4
  def initialize(manifest, dest_dir, zip_file)
5
5
  @manifest = manifest
6
- @dest_dir = dest_dir
7
- @items = manifest.organizations.organization.item.items
6
+ @dest_name = dest_dir
7
+ @root_items = manifest.organizations.organization.item.items
8
8
  end
9
9
 
10
10
  def generate
11
- FileUtils.mkdir_p(@dest_dir)
11
+ FileUtils.mkdir_p(@dest_name)
12
12
  template = File.expand_path(TEMPLATE_DIR + 'index.html.erb', __FILE__)
13
- path = File.join(@dest_dir, 'index.html')
13
+ path = File.join(@dest_name, 'index.html')
14
14
 
15
15
  #FileUtils.mkdir_p(File.dirname(path))
16
16
  File.open(path, 'w') do |file|
@@ -1,11 +1,22 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
3
- <head><title>Table of contents</title></head>
4
- <body><nav xmlns="http://www.w3.org/1999/xhtml" class="book" epub:type="toc">
5
- <ol>
6
- <% @items.each do |item| %>
7
- <li><a href="<%= item.identifierref %>.html"><%= item.title %></a></li>
8
- <% end %>
9
- </ol>
10
- </nav></body>
3
+ <head><title>Table of contents</title></head>
4
+ <body>
5
+ <nav xmlns="http://www.w3.org/1999/xhtml" class="book" epub:type="toc">
6
+ <% @root_items.select{|ri|ri.items.any?}.each_with_index do |root, chapter_index| %>
7
+ <h2>Chaper <%= chapter_index + 1 %>: <%= root.title %></h2>
8
+
9
+ <ol>
10
+ <% root.items.each do |item| %>
11
+ <% if item.identifierref && item.identifierref != '' %>
12
+ <li><a href="<%= item.identifierref %>.html"><%= item.title %></a></li>
13
+ <% else %>
14
+ <!-- Could have sub headers in index, but may only appropriate for pages -->
15
+ <!--<h3><%= item.title %></h3>-->
16
+ <% end %>
17
+ <% end %>
18
+ </ol>
19
+ <% end %>
20
+ </nav>
21
+ </body>
11
22
  </html>
@@ -5,7 +5,7 @@
5
5
  </head>
6
6
  <body>
7
7
  <ul>
8
- <% @items.each do |item| %>
8
+ <% @root_items.each do |item| %>
9
9
  <li><%= item.identifier %></li>
10
10
  <% end %>
11
11
  </ul>
@@ -1,3 +1,3 @@
1
1
  module CC2HTML
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -29,16 +29,7 @@ module IMS::CC
29
29
 
30
30
  def post_process
31
31
  parse_references
32
- connect_resources_to_org_item
33
- end
34
-
35
- def connect_resources_to_org_item
36
- self.organizations.organization.item.items.each do |item|
37
- next unless item.identifierref
38
- if res = self.resources.find_by_identifier(item.identifierref)
39
- item.resource = res
40
- end
41
- end
32
+ organizations.attach_resources_to_items(resources)
42
33
  end
43
34
 
44
35
  def parse_references
@@ -10,7 +10,33 @@ module Organizations
10
10
  attribute :identifierref, String
11
11
  element :title, String
12
12
 
13
- has_many :items, Item
13
+ # This is so that it only select parent items of itself,
14
+ # otherwise HappyMapper does .// instead of ./
15
+ # can this reference its own namespace somehow?
16
+ has_many :items, Item, :xpath => "./#{HappyMapper::DEFAULT_NS}:item"
17
+
18
+ def find_by_identifier(id)
19
+ if id == identifier
20
+ self
21
+ else
22
+ items.each do |i|
23
+ if item = i.find_by_identifier(id)
24
+ return item
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def attach_resources(resources)
31
+ @resource = resources.find_by_identifier(identifierref) if identifierref
32
+ items.each { |i| i.attach_resources(resources) }
33
+ end
34
+
35
+ def all_items(res=[])
36
+ res << self
37
+ items.each{|i|i.all_items(res)}
38
+ res
39
+ end
14
40
  end
15
41
 
16
42
  class Organization
@@ -29,7 +55,11 @@ module Organizations
29
55
  has_one :organization, Organization
30
56
 
31
57
  def find_item_by_identifier(id)
32
- self.organization.item.items.find{|i| i.identifier == id}
58
+ organization.item.find_by_identifier(id)
59
+ end
60
+
61
+ def attach_resources_to_items(resources)
62
+ organization.item.attach_resources(resources)
33
63
  end
34
64
  end
35
65
 
@@ -1,10 +1,10 @@
1
1
  module IMS::CC
2
2
  class Topic
3
3
  include HappyMapper
4
- #register_namespace('http://www.imsglobal.org/xsd/imsccv1p3/imsdt_v1p3', 'dt3')
5
- #register_namespace('http://www.imsglobal.org/xsd/imsccv1p1/imsdt_v1p1', 'dt1')
4
+ # register_namespace('http://www.imsglobal.org/xsd/imsccv1p3/imsdt_v1p3', 'dt3')
5
+ # register_namespace('http://www.imsglobal.org/xsd/imsccv1p1/imsdt_v1p1', 'dt1')
6
6
  namespace 'http://www.imsglobal.org/xsd/imsccv1p3/imsdt_v1p3'
7
- #namespace 'http://www.imsglobal.org/xsd/imsccv1p1/imsdt_v1p1'
7
+ # namespace 'http://www.imsglobal.org/xsd/imsccv1p1/imsdt_v1p1'
8
8
 
9
9
  tag 'topic'
10
10
  element :title, String
@@ -59,7 +59,16 @@
59
59
  <item identifier="I_00003" identifierref="Resource3">
60
60
  <title>Open2.net</title>
61
61
  </item>
62
- <item identifier="I_00004" identifierref="Resource4">
62
+ <item identifier="I_00003">
63
+ <title>Child Folder</title>
64
+ <item identifier="I_00004" identifierref="Resource4">
65
+ <title>LTI Launch</title>
66
+ </item>
67
+ </item>
68
+ </item>
69
+ <item identifier="I_2">
70
+ <title>Folder 2</title>
71
+ <item identifier="I_00005" identifierref="Resource4">
63
72
  <title>LTI Launch</title>
64
73
  </item>
65
74
  </item>
@@ -14,20 +14,41 @@ class TestUnitOrganizations < Minitest::Test
14
14
  assert_equal 'rooted-hierarchy', @orgs.organization.structure
15
15
  end
16
16
 
17
- # have to figure out why happy mapper gets all items instead of just 1st children
18
- #def test_it_creates_item_tree
19
- # assert_equal 1, @orgs.organization.item.items.count
20
- # assert_equal 4, @orgs.organization.item.items[0].count
21
- #end
17
+ def test_it_creates_item_tree
18
+ assert_instance_of IMS::CC::Organizations::Item, @orgs.organization.item
19
+ assert_equal 2, @orgs.organization.item.items.count
20
+ assert_equal 4, @orgs.organization.item.items[0].items.count
21
+ assert_equal 1, @orgs.organization.item.items[0].items[3].items.count
22
+ assert_equal 1, @orgs.organization.item.items[1].items.count
23
+ end
22
24
 
23
25
  def test_gets_item_info
24
- assert_equal "I_00000", @orgs.organization.item.items[0].identifier
25
- assert_equal "CCv1.3 With Assignment", @orgs.organization.item.items[0].title
26
- assert_equal '', @orgs.organization.item.items[0].identifierref
27
-
28
- assert_equal "I_00001", @orgs.organization.item.items[1].identifier
29
- assert_equal "Cool Assignment", @orgs.organization.item.items[1].title
30
- assert_equal "Resource1", @orgs.organization.item.items[1].identifierref
26
+ folder1 = @orgs.organization.item.items[0]
27
+ assert_equal "I_00000", folder1.identifier
28
+ assert_equal "CCv1.3 With Assignment", folder1.title
29
+ assert_equal '', folder1.identifierref
30
+
31
+ assert_equal "I_00001", folder1.items[0].identifier
32
+ assert_equal "Cool Assignment", folder1.items[0].title
33
+ assert_equal "Resource1", folder1.items[0].identifierref
34
+
35
+ sub_folder = folder1.items.last
36
+ assert_equal "I_00003", sub_folder.identifier
37
+ assert_equal "Child Folder", sub_folder.title
38
+ assert_equal "", sub_folder.identifierref
39
+
40
+ assert_equal "I_00004", sub_folder.items[0].identifier
41
+ assert_equal "LTI Launch", sub_folder.items[0].title
42
+ assert_equal "Resource4", sub_folder.items[0].identifierref
43
+
44
+ folder2 = @orgs.organization.item.items[1]
45
+ assert_equal "I_2", folder2.identifier
46
+ assert_equal "Folder 2", folder2.title
47
+ assert_equal "", folder2.identifierref
48
+
49
+ assert_equal "I_00005", folder2.items[0].identifier
50
+ assert_equal "LTI Launch", folder2.items[0].title
51
+ assert_equal "Resource4", folder2.items[0].identifierref
31
52
  end
32
53
 
33
54
  def test_item_references_resource
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cc2html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-11 00:00:00.000000000 Z
12
+ date: 2014-05-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rubyzip
@@ -196,6 +196,7 @@ extensions: []
196
196
  extra_rdoc_files:
197
197
  - LICENSE
198
198
  files:
199
+ - .ruby-version
199
200
  - Gemfile
200
201
  - Gemfile.lock
201
202
  - Guardfile