active_copy 1.0.0.pre

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.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +14 -0
  5. data/Gemfile.lock +116 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +77 -0
  8. data/Rakefile +9 -0
  9. data/active_copy.gemspec +27 -0
  10. data/config/initializers/register_active_copy_template_handler.rb +4 -0
  11. data/lib/active_copy.rb +21 -0
  12. data/lib/active_copy/attributes.rb +58 -0
  13. data/lib/active_copy/base.rb +34 -0
  14. data/lib/active_copy/finders.rb +61 -0
  15. data/lib/active_copy/markdown.rb +34 -0
  16. data/lib/active_copy/paths.rb +54 -0
  17. data/lib/active_copy/renderer.rb +13 -0
  18. data/lib/active_copy/source.rb +24 -0
  19. data/lib/active_copy/template.rb +20 -0
  20. data/lib/active_copy/version.rb +3 -0
  21. data/lib/active_copy/view_helper.rb +17 -0
  22. data/lib/generators/copy/USAGE +14 -0
  23. data/lib/generators/copy/copy_generator.rb +34 -0
  24. data/lib/generators/copy/templates/USAGE.erb +13 -0
  25. data/lib/generators/copy/templates/generator.rb.erb +39 -0
  26. data/lib/generators/copy/templates/model.rb.erb +3 -0
  27. data/lib/generators/copy/templates/test.rb.erb +5 -0
  28. data/lib/generators/copy/templates/view.md.erb +8 -0
  29. data/lib/tasks/active_copy_tasks.rake +4 -0
  30. data/spec/active_copy/.keep +0 -0
  31. data/spec/active_copy/base_spec.rb +31 -0
  32. data/spec/dummy/README.rdoc +28 -0
  33. data/spec/dummy/Rakefile +6 -0
  34. data/spec/dummy/app/assets/images/.keep +0 -0
  35. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  36. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  37. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  38. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  39. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  40. data/spec/dummy/app/mailers/.keep +0 -0
  41. data/spec/dummy/app/models/.keep +0 -0
  42. data/spec/dummy/app/models/concerns/.keep +0 -0
  43. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  44. data/spec/dummy/bin/bundle +3 -0
  45. data/spec/dummy/bin/rails +4 -0
  46. data/spec/dummy/bin/rake +4 -0
  47. data/spec/dummy/config.ru +4 -0
  48. data/spec/dummy/config/application.rb +23 -0
  49. data/spec/dummy/config/boot.rb +5 -0
  50. data/spec/dummy/config/database.yml +25 -0
  51. data/spec/dummy/config/environment.rb +5 -0
  52. data/spec/dummy/config/environments/development.rb +29 -0
  53. data/spec/dummy/config/environments/production.rb +80 -0
  54. data/spec/dummy/config/environments/test.rb +36 -0
  55. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  56. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  57. data/spec/dummy/config/initializers/inflections.rb +16 -0
  58. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  59. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  60. data/spec/dummy/config/initializers/session_store.rb +3 -0
  61. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  62. data/spec/dummy/config/locales/en.yml +23 -0
  63. data/spec/dummy/config/routes.rb +56 -0
  64. data/spec/dummy/lib/assets/.keep +0 -0
  65. data/spec/dummy/log/.keep +0 -0
  66. data/spec/dummy/public/404.html +58 -0
  67. data/spec/dummy/public/422.html +58 -0
  68. data/spec/dummy/public/500.html +57 -0
  69. data/spec/dummy/public/favicon.ico +0 -0
  70. data/spec/dummy/spec/fixtures/basic_pages/content/about.md +5 -0
  71. data/spec/spec_helper.rb +11 -0
  72. data/spec/support/basic_page.rb +4 -0
  73. metadata +256 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f227f3674215e99c1215397cbb5bef2284592aa
4
+ data.tar.gz: 7547b592fb262663e9bafddcbfc8a2786f67352f
5
+ SHA512:
6
+ metadata.gz: 12dd750c3aad0897785a75d86bae5ff9346bcd7ba1aeaa7e43d5eb4801d9f21861d90617d6713fe2bbe8c4b394100960674c46cd91c5bb26dad1b834c1019dd3
7
+ data.tar.gz: 07b3e2d159e133d21df8985c457b08d889ee744c1e741d41ad8424a2362214e06d41f48e4db18efb1590ab9c046feee30f9cede1421939bec109c4a076981e82
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ spec/dummy/db/*.sqlite3
5
+ spec/dummy/db/*.sqlite3-journal
6
+ spec/dummy/log/*.log
7
+ spec/dummy/tmp/
8
+ spec/dummy/.sass-cache
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format=documentation
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in active_copy.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # Declare any dependencies that are still in development here instead of in
9
+ # your gemspec. These might include edge Rails or gems from your path or
10
+ # Git. Remember to move these dependencies to your gemspec before releasing
11
+ # your gem to rubygems.org.
12
+
13
+ # To use debugger
14
+ # gem 'debugger'
data/Gemfile.lock ADDED
@@ -0,0 +1,116 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ active_copy (1.0.0.pre)
5
+ pygments.rb (~> 0.3)
6
+ rails
7
+ redcarpet
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionmailer (4.0.1)
13
+ actionpack (= 4.0.1)
14
+ mail (~> 2.5.4)
15
+ actionpack (4.0.1)
16
+ activesupport (= 4.0.1)
17
+ builder (~> 3.1.0)
18
+ erubis (~> 2.7.0)
19
+ rack (~> 1.5.2)
20
+ rack-test (~> 0.6.2)
21
+ activemodel (4.0.1)
22
+ activesupport (= 4.0.1)
23
+ builder (~> 3.1.0)
24
+ activerecord (4.0.1)
25
+ activemodel (= 4.0.1)
26
+ activerecord-deprecated_finders (~> 1.0.2)
27
+ activesupport (= 4.0.1)
28
+ arel (~> 4.0.0)
29
+ activerecord-deprecated_finders (1.0.3)
30
+ activesupport (4.0.1)
31
+ i18n (~> 0.6, >= 0.6.4)
32
+ minitest (~> 4.2)
33
+ multi_json (~> 1.3)
34
+ thread_safe (~> 0.1)
35
+ tzinfo (~> 0.3.37)
36
+ arel (4.0.1)
37
+ atomic (1.1.14)
38
+ builder (3.1.4)
39
+ coderay (1.1.0)
40
+ diff-lcs (1.2.5)
41
+ erubis (2.7.0)
42
+ hike (1.2.3)
43
+ i18n (0.6.5)
44
+ mail (2.5.4)
45
+ mime-types (~> 1.16)
46
+ treetop (~> 1.4.8)
47
+ method_source (0.8.2)
48
+ mime-types (1.25.1)
49
+ minitest (4.7.5)
50
+ multi_json (1.8.2)
51
+ polyglot (0.3.3)
52
+ posix-spawn (0.3.6)
53
+ pry (0.9.12.4)
54
+ coderay (~> 1.0)
55
+ method_source (~> 0.8)
56
+ slop (~> 3.4)
57
+ pygments.rb (0.5.4)
58
+ posix-spawn (~> 0.3.6)
59
+ yajl-ruby (~> 1.1.0)
60
+ rack (1.5.2)
61
+ rack-test (0.6.2)
62
+ rack (>= 1.0)
63
+ rails (4.0.1)
64
+ actionmailer (= 4.0.1)
65
+ actionpack (= 4.0.1)
66
+ activerecord (= 4.0.1)
67
+ activesupport (= 4.0.1)
68
+ bundler (>= 1.3.0, < 2.0)
69
+ railties (= 4.0.1)
70
+ sprockets-rails (~> 2.0.0)
71
+ railties (4.0.1)
72
+ actionpack (= 4.0.1)
73
+ activesupport (= 4.0.1)
74
+ rake (>= 0.8.7)
75
+ thor (>= 0.18.1, < 2.0)
76
+ rake (10.1.0)
77
+ redcarpet (3.0.0)
78
+ rspec (2.14.1)
79
+ rspec-core (~> 2.14.0)
80
+ rspec-expectations (~> 2.14.0)
81
+ rspec-mocks (~> 2.14.0)
82
+ rspec-core (2.14.7)
83
+ rspec-expectations (2.14.4)
84
+ diff-lcs (>= 1.1.3, < 2.0)
85
+ rspec-mocks (2.14.4)
86
+ slop (3.4.7)
87
+ sprockets (2.10.1)
88
+ hike (~> 1.2)
89
+ multi_json (~> 1.0)
90
+ rack (~> 1.0)
91
+ tilt (~> 1.1, != 1.3.0)
92
+ sprockets-rails (2.0.1)
93
+ actionpack (>= 3.0)
94
+ activesupport (>= 3.0)
95
+ sprockets (~> 2.8)
96
+ sqlite3 (1.3.8)
97
+ thor (0.18.1)
98
+ thread_safe (0.1.3)
99
+ atomic
100
+ tilt (1.4.1)
101
+ treetop (1.4.15)
102
+ polyglot
103
+ polyglot (>= 0.3.1)
104
+ tzinfo (0.3.38)
105
+ yajl-ruby (1.1.0)
106
+ yard (0.8.7.3)
107
+
108
+ PLATFORMS
109
+ ruby
110
+
111
+ DEPENDENCIES
112
+ active_copy!
113
+ pry
114
+ rspec
115
+ sqlite3
116
+ yard
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # ActiveCopy
2
+
3
+ ActiveCopy is a Rails model layer for reading from static page files.
4
+ Inspired by [Jekyll][jekyll], it hacks ActionView to allow for storage
5
+ of static page content inside app/views as YAML Front Matter/Markdown.
6
+
7
+ Although it's still very much a work in progress, ActiveCopy is being
8
+ used in production on <http://psychedeli.ca>.
9
+
10
+ ## Setup
11
+
12
+ Add to Gemfile:
13
+
14
+ ```ruby
15
+ gem 'active_copy'
16
+ ```
17
+
18
+ And generate a model:
19
+
20
+ ```bash
21
+ $ rails generate copy article
22
+ ```
23
+
24
+ You'll get this as **app/models/article.rb**:
25
+
26
+ ```ruby
27
+ class Article < ActiveCopy::Base
28
+ attr_accessible :title
29
+ end
30
+ ```
31
+
32
+ You'll also see a generator pop up in **lib/generators** that
33
+ corresponds to the name you gave the original generator. The `copy`
34
+ generator actually "generates a generator" so that you can more easily
35
+ generate your custom model records (files).
36
+
37
+ ## Usage
38
+
39
+ You can define articles in **app/views/articles/content/your-article.md**:
40
+
41
+ ```markdown
42
+ ---
43
+ title: "The title of your article"
44
+ ---
45
+
46
+ Hi I'm a static article.
47
+ ```
48
+
49
+ Retrieve that article from a param in your route:
50
+
51
+ ```ruby
52
+ class ArticlesController < ApplicationController
53
+ def show
54
+ @article = Article.find params[:id]
55
+
56
+ respond_with @article
57
+ end
58
+ end
59
+ ```
60
+
61
+ And show the article in your view:
62
+
63
+ ```haml
64
+ #article
65
+ %h1= @article.name
66
+ .content= @article.content
67
+ ```
68
+
69
+ ## Contributing
70
+
71
+ You can contribute by making a GitHub pull request. Please include tests
72
+ with your feature/bug fix and an ample description as to why you're
73
+ fixing the bug.
74
+
75
+ ### Roadmap
76
+
77
+ - Generators
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/setup'
2
+ require 'rdoc/task'
3
+ require 'rspec/core/rake_task'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ RSpec::Core::RakeTask.new :test
8
+
9
+ task :default => %w(test build)
@@ -0,0 +1,27 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ # Maintain your gem's version:
4
+ require "active_copy/version"
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+ s.name = "active_copy"
9
+ s.version = ActiveCopy::VERSION
10
+ s.authors = ["Tom Scott"]
11
+ s.email = ["tubbo@psychedeli.ca"]
12
+ s.homepage = "http://github.com/tubbo/active_copy"
13
+ s.summary = "Use the Rails model layer as a backend for static files"
14
+ s.description = s.summary
15
+
16
+ s.files = `git ls-files`.split "\n"
17
+ s.test_files = s.files.grep(/\Aspec/)
18
+
19
+ s.add_dependency "rails"
20
+ s.add_dependency 'pygments.rb', '~> 0.3'
21
+ s.add_dependency 'redcarpet'
22
+
23
+ s.add_development_dependency "sqlite3"
24
+ s.add_development_dependency "rspec"
25
+ s.add_development_dependency "yard"
26
+ s.add_development_dependency "pry"
27
+ end
@@ -0,0 +1,4 @@
1
+ require 'active_copy'
2
+
3
+ # Add the Markdown template handler.
4
+ ActionView::Template.register_template_handler :md, ActiveCopy::Template
@@ -0,0 +1,21 @@
1
+ require 'active_copy/attributes'
2
+ require 'active_copy/base'
3
+ require 'active_copy/markdown'
4
+ require 'active_copy/template'
5
+ require 'active_copy/view_helper'
6
+ require 'active_copy/version'
7
+
8
+ # ActiveCopy reads Markdown files in +app/documents+ instead of a
9
+ # database for your Rails models. Inspired by Jekyll, it uses compatible
10
+ # YAML front matter to set up the metadata for each page, then renders its
11
+ # content using +ActionView+. In production, +Rake+ tasks are provided to
12
+ # precompile the Markdown files to pure HTML for performance purposes.
13
+ module ActiveCopy
14
+ def self.content_path
15
+ @content_path = if ENV['RAILS_ENV'] == 'test'
16
+ 'spec/fixtures'
17
+ else
18
+ 'app/views'
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+ require 'active_support/core_ext/string/inflections'
3
+
4
+ module ActiveCopy
5
+ # Attribute storage and handling for +ActiveCopy+ models.
6
+ module Attributes
7
+ extend ActiveSupport::Concern
8
+
9
+ DEFAULT_PATH = "public/#{self.class.name.parameterize.pluralize}"
10
+ DEFAULT_ATTRS = [:layout]
11
+
12
+ included do
13
+ class_attribute :_accessible_attributes
14
+ class_attribute :_deployment_path
15
+ end
16
+
17
+ module ClassMethods
18
+ def attr_accessible(*args)
19
+ if self._accessible_attributes.nil?
20
+ self._accessible_attributes = []
21
+ end
22
+
23
+ args.each do |attribute|
24
+ self._accessible_attributes << attribute
25
+ end
26
+ end
27
+
28
+ def deploy_to file_path
29
+ self._deployment_path = file_path
30
+ end
31
+
32
+ def accessible_attrs
33
+ return DEFAULT_ATTRS if self._accessible_attributes.nil?
34
+ self._accessible_attributes += DEFAULT_ATTRS
35
+ end
36
+
37
+ def deployment_path
38
+ self._deployment_path || "#{DEFAULT_PATH}/#{self.id}.html"
39
+ end
40
+ end
41
+
42
+ # Take YAML front matter given by id.
43
+ def attributes
44
+ @attributes ||= yaml_front_matter.with_indifferent_access
45
+ end
46
+
47
+ protected
48
+ def attribute? key
49
+ self.class.accessible_attrs.include? key.to_sym
50
+ end
51
+
52
+ private
53
+ def yaml_front_matter
54
+ HashWithIndifferentAccess.new \
55
+ YAML::load(raw_source.split("---\n")[1])
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,34 @@
1
+ require 'active_model'
2
+ require 'active_copy/attributes'
3
+ require 'active_copy/finders'
4
+ require 'active_copy/paths'
5
+ require 'active_copy/source'
6
+
7
+ # Base class for an +ActiveCopy+ model.
8
+
9
+ module ActiveCopy
10
+ class Base
11
+ include ActiveModel::Model
12
+ include Attributes, Finders, Paths, Source
13
+
14
+ attr_accessor :id
15
+
16
+ # Serialize comma-separated tags to an array.
17
+ def tags
18
+ attributes[:tags].split(',').map(&:strip)
19
+ end
20
+
21
+ class << self
22
+ # New and create are the same thing.
23
+ alias create new
24
+ end
25
+
26
+ # Files are persisted when they are present on disk.
27
+ alias persisted? present?
28
+
29
+ def method_missing method, *arguments
30
+ super method, *arguments unless attribute? "#{method}"
31
+ attributes[method]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,61 @@
1
+
2
+ # Methods for finding records on the filesystem.
3
+
4
+ module ActiveCopy
5
+ module Finders
6
+ extend ActiveSupport::Concern
7
+
8
+ # Test if the query matches this particular model.
9
+ def matches? query
10
+ query.reduce(true) do |matches, (key, value)|
11
+ matches = if key == 'tag'
12
+ return false unless tags.present?
13
+ tags.include? value
14
+ else
15
+ attributes[key] == value
16
+ end
17
+ end
18
+ end
19
+
20
+ module ClassMethods
21
+ # Return the folder where all documents are stored for this model.
22
+ def collection_path
23
+ @collection_path ||= "#{ActiveCopy.content_path}/#{name.tableize}/content"
24
+ end
25
+
26
+ # Find this model by its filename.
27
+ def find by_filename
28
+ if File.exists? "#{Rails.root}/#{collection_path}/#{by_filename}.md"
29
+ new id: by_filename
30
+ else
31
+ nil
32
+ end
33
+ end
34
+
35
+ # Read all files from the +collection_path+, then instantiate them
36
+ # as members of this model. Return as an +Array+.
37
+ def all
38
+ Dir["#{absolute_collection_path}/*.md"].reduce([]) do |articles, md_path|
39
+ unless md_path == "#{Rails.root}/#{collection_path}"
40
+ file_name = File.basename(md_path).gsub('.md', '')
41
+ articles << self.new(id: file_name)
42
+ end
43
+ end
44
+ end
45
+
46
+ # Look for all of the matching key/value pairs in the YAML front
47
+ # matter, and return an array of models that match them.
48
+ def where query={}
49
+ all.reject { |a| a.nil? }.reduce([]) do |results, article|
50
+ results << article if article.matches? query
51
+ results
52
+ end
53
+ end
54
+
55
+ private
56
+ def absolute_collection_path
57
+ "#{Rails.root}/#{collection_path}"
58
+ end
59
+ end
60
+ end
61
+ end