higml 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", ">= 1.3.0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.5.2)
6
+ bundler (~> 1.0.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rake (0.8.7)
10
+ rcov (0.9.9)
11
+ rspec (1.3.1)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ bundler (~> 1.0.0)
18
+ jeweler (~> 1.5.2)
19
+ rcov
20
+ rspec (>= 1.3.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Daniel Higginbotham
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.markdown ADDED
@@ -0,0 +1,111 @@
1
+ higml
2
+ =====
3
+
4
+ Overview
5
+ --------
6
+
7
+ Higml is a terse format for converting an input hash to an output hash.
8
+
9
+ Example Higml and input:
10
+
11
+ # Higml
12
+ action:show
13
+ :pageName Search Results
14
+ :keywords= keywords
15
+
16
+ filter
17
+ :filter_terms= filter_terms
18
+
19
+ # Input hash
20
+ {
21
+ :action => "show",
22
+ :filter => "any value"
23
+ }
24
+
25
+ This output is produced:
26
+
27
+ {
28
+ :pageName => "Search Results",
29
+ :keywords => ... #depends on value of "keywords" method in given context
30
+ :filter_terms => ... #depends on value of "filter_terms" method in given context
31
+ }
32
+
33
+ To get a better understand of _what_ Higml does, go through spec/higml_spec.rb and the corresponding .higml files in spec/fixtures.
34
+
35
+ Why would you want to use it? The original use case was generating a json object for analytics. The json object had different fields and values depending on what section of the site and individual page were being viewed. When viewing a profile, the json might be
36
+
37
+ {
38
+ pageName: "Profile: 4320",
39
+ section: "Profiles"
40
+ }
41
+
42
+ whereas search might look like
43
+
44
+ {
45
+ pageName: "Search: 'robert'",
46
+ section: "Search"
47
+ }
48
+
49
+ The actual json was much more complicated, containing about 20 keys. Writing the mapping between input and output in higml allowed my coworkers and I to quickly understand what the json would be for a given page, or why the json was the way it was. Example .higml files can be found in /examples.
50
+
51
+ Syntax
52
+ ------
53
+
54
+ Example:
55
+
56
+ @import application.higml
57
+ action:show, action:new
58
+ :pageName Search Results
59
+ :keywords= keywords
60
+
61
+ q:rutabagas
62
+ :rutabagas true
63
+
64
+ filter
65
+ :filter_terms= filter_terms
66
+
67
+ <dl>
68
+ <dt>@import appication.higml</dt>
69
+ <dd>acts as if the contents of application.higml were located where @import is</dd>
70
+ <dt>action:show, action:new</dt>
71
+ <dd>If the input hash has a value of "show" _or_ "new" for the key :action, then use the mapping that follows</dd>
72
+ <dt>:pageName Search Results</dt>
73
+ <dd>Output hash has a value of "Search Results" for the :pageName key; constant string</dd>
74
+ <dt>:keywords= keywords</dt>
75
+ <dd>Value of :keywords in output hash is whatever "keywords" evaluates to in the Higml mapper_context; let's you have dynamic values</dd>
76
+ <dt>q:rutabagas</dt>
77
+ <dd>If input hash satisfies action:show _or_ action:new, _and_ it has a value of "rutabagas" for :q, then apply the mapping that follows</dd>
78
+ <dt>filter</dt>
79
+ <dd>If input hash has a key of :filter at all (regardless of :q but dependent on :action), then apply mapping that follows</dd>
80
+ </dl>
81
+
82
+ Config
83
+ ------
84
+ Use Higml.config.x to set these
85
+
86
+ <dl>
87
+ <dt>config_directory</dt>
88
+ <dd>Where higml-config.yml is stored #this may be overkill :(</dd>
89
+ <dt>higml_directory</dt>
90
+ <dd>Where all the .higml files are stored</dd>
91
+ <dt>global_pairs</dt>
92
+ <dd>should be hash; used as base hash that result of mapping is merged on to</dd>
93
+ </dl>
94
+
95
+ Contributing to higml
96
+ ---------------------
97
+
98
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
99
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
100
+ * Fork the project
101
+ * Start a feature/bugfix branch
102
+ * Commit and push until you are happy with your contribution
103
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
104
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
105
+
106
+ Copyright
107
+ ---------
108
+
109
+ Copyright (c) 2010 Daniel Higginbotham. See LICENSE.txt for
110
+ further details.
111
+
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "higml"
16
+ gem.homepage = "http://github.com/flyingmachine/higml"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Higml is a terse format for converting an input hash to an output hash.}
19
+ gem.description = %Q{Higml is a terse format for converting a static input hash to a dynamic output hash.}
20
+ gem.email = "daniel@flyingmachinestudios.com"
21
+ gem.authors = ["Daniel Higginbotham"]
22
+ end
23
+ Jeweler::RubygemsDotOrgTasks.new
24
+
25
+ require 'spec/rake/spectask'
26
+ Spec::Rake::SpecTask.new(:spec) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
30
+
31
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.pattern = 'spec/**/*_spec.rb'
34
+ spec.rcov = true
35
+ end
36
+
37
+ task :default => :spec
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "higml #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,4 @@
1
+ @import application.higml
2
+
3
+ action:index
4
+ :pageName ManagePermissions
@@ -0,0 +1,18 @@
1
+ :charSet UTF-8
2
+ :currencyCode USD
3
+ :linkLeaveQueryString= false
4
+ :linkTrackVars None
5
+ :linkTrackEvents None
6
+
7
+ :trackDownloadLinks= true
8
+ :trackExternalLinks= true
9
+ :trackInlineStats= true
10
+ :linkDownloadFileTypes zip,wav,mp3,mov,mpg,avi,doc,pdf,xls,ppt
11
+ :linkInternalFilters= "javascript:,#{request.host}"
12
+
13
+ :pidx= current_user.id
14
+ :skill_level= current_user_type
15
+ :site_name My Site
16
+ :session_id= request.session_options[:id]
17
+ :timestamp= Time.now.strftime("%Y/%m/%d %H:%M:%S %p")
18
+ :country= current_user_country
@@ -0,0 +1,4 @@
1
+ @import application.higml
2
+
3
+ action:show
4
+ :pageName= @article.title
@@ -0,0 +1,4 @@
1
+ @import application.higml
2
+
3
+ action:show
4
+ :pageName ContactUs
@@ -0,0 +1,2 @@
1
+ @import application.higml
2
+ :pageName Home
@@ -0,0 +1,9 @@
1
+ @import application.higml
2
+
3
+ :channel Messages
4
+
5
+ action:index
6
+ :pageName List Messages
7
+
8
+ action:show
9
+ :pageName= "Message #{@message.id}"
@@ -0,0 +1,9 @@
1
+ @import application.higml
2
+
3
+ id:privacy_policy
4
+ :channel PrivacyPolicy
5
+ :pageName PrivacyPolicy
6
+
7
+ id:terms_of_use
8
+ :channel TermsOfUse
9
+ :pageName TermsOfUse
@@ -0,0 +1,17 @@
1
+ @import application.higml
2
+
3
+ action:show
4
+ :channel Profile_PersonalInformation
5
+ :pageName= "Profile_PersonalInformation #{@member.id}"
6
+
7
+ viewing_own
8
+ :channel MyProfile_PersonalInformation
9
+ :pageName= "MyProfile_PersonalInformation #{@member.id}"
10
+
11
+ action:edit
12
+ :channel MyProfile_Edit
13
+ :pageName= "MyProfile_Edit #{@member.id}"
14
+
15
+ action:edit_preferences
16
+ :channel ManageSetting
17
+ :pageName= "ManageSetting #{current_user.id}"
@@ -0,0 +1,35 @@
1
+ @import application.higml
2
+
3
+ action:show, action:new
4
+ :channel Search
5
+ :search_term= @parser.keywords
6
+ :search_count= total_search_results
7
+ :search_resource_type= @parser.search_type
8
+ :search_fields= omniture_search_fields
9
+
10
+ action:show
11
+ :pageName= "Saved Search #{params[:id]}"
12
+ :search_type saved
13
+
14
+ action:new
15
+ :pageName New Search
16
+
17
+ search_type
18
+ :pageName Performed Search
19
+ :search_type= omniture_search_type
20
+
21
+ filter
22
+ :filter_type= filter_types
23
+ :filter_term= filter_terms
24
+ :search_type filtered
25
+
26
+ action:create
27
+ :channel Search Saved
28
+ :pageName= "Search Saved #{@search.id}"
29
+
30
+ action:destroy
31
+ :channel Search Deleted
32
+ :pageName= "Search Deleted #{@search.id}"
33
+
34
+ search_origin
35
+ :search_origin= params[:search_origin]
@@ -0,0 +1,4 @@
1
+ @import application.higml
2
+
3
+ :channel SimulateScenarios
4
+ :pageName SimulateScenarios
data/higml.gemspec ADDED
@@ -0,0 +1,92 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{higml}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Daniel Higginbotham"]
12
+ s.date = %q{2010-12-23}
13
+ s.description = %q{Higml is a terse format for converting a static input hash to a dynamic output hash.}
14
+ s.email = %q{daniel@flyingmachinestudios.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.markdown",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "examples/affiliations.higml",
29
+ "examples/application.higml",
30
+ "examples/articles.higml",
31
+ "examples/contacts.higml",
32
+ "examples/homes.higml",
33
+ "examples/messages.higml",
34
+ "examples/pages.higml",
35
+ "examples/profiles.higml",
36
+ "examples/searches.higml",
37
+ "examples/simulate.higml",
38
+ "higml.gemspec",
39
+ "lib/higml.rb",
40
+ "lib/higml/applier.rb",
41
+ "lib/higml/config.rb",
42
+ "lib/higml/node.rb",
43
+ "lib/higml/parser.rb",
44
+ "lib/higml/value.rb",
45
+ "spec/fixtures/application.higml",
46
+ "spec/fixtures/higml-config.yml",
47
+ "spec/fixtures/search.higml",
48
+ "spec/fixtures/selectors_with_groups.higml",
49
+ "spec/fixtures/with_import.higml",
50
+ "spec/higml_spec.rb",
51
+ "spec/lib/higml/applier_spec.rb",
52
+ "spec/lib/higml/config_spec.rb",
53
+ "spec/lib/higml/parser_spec.rb",
54
+ "spec/spec.opts",
55
+ "spec/spec_helper.rb"
56
+ ]
57
+ s.homepage = %q{http://github.com/flyingmachine/higml}
58
+ s.licenses = ["MIT"]
59
+ s.require_paths = ["lib"]
60
+ s.rubygems_version = %q{1.3.7}
61
+ s.summary = %q{Higml is a terse format for converting an input hash to an output hash.}
62
+ s.test_files = [
63
+ "spec/higml_spec.rb",
64
+ "spec/lib/higml/applier_spec.rb",
65
+ "spec/lib/higml/config_spec.rb",
66
+ "spec/lib/higml/parser_spec.rb",
67
+ "spec/spec_helper.rb"
68
+ ]
69
+
70
+ if s.respond_to? :specification_version then
71
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
72
+ s.specification_version = 3
73
+
74
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
75
+ s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
76
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
77
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
78
+ s.add_development_dependency(%q<rcov>, [">= 0"])
79
+ else
80
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
81
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
82
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
83
+ s.add_dependency(%q<rcov>, [">= 0"])
84
+ end
85
+ else
86
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
87
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
88
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
89
+ s.add_dependency(%q<rcov>, [">= 0"])
90
+ end
91
+ end
92
+
@@ -0,0 +1,57 @@
1
+ module Higml
2
+ class Applier
3
+ def initialize(input, tree, priority_map, mapper_context)
4
+ @input = input
5
+ @tree = tree
6
+ @mapper_context = mapper_context
7
+ @priority_map = priority_map
8
+ end
9
+
10
+ def result
11
+ @result = {}
12
+ apply_tree
13
+ Higml.config.global_pairs.merge@result.merge(@priority_map)
14
+ end
15
+
16
+ def apply_tree
17
+ apply_node(@tree)
18
+ end
19
+
20
+ def apply_node(node)
21
+ if node.selector.nil? || selector_matches?(node.selector)
22
+ apply_values(node.values)
23
+ node.children.each do |child_node|
24
+ apply_node(child_node)
25
+ end
26
+ end
27
+ end
28
+
29
+ def apply_values(node_values)
30
+ node_values.each do |value|
31
+ next if priority_keys.include? value.key
32
+ if value.static?
33
+ @result[value.key] = value.raw_value
34
+ else
35
+ @result[value.key] = @mapper_context.instance_eval(value.raw_value)
36
+ end
37
+ end
38
+ end
39
+
40
+ # REFACTOR to selector class
41
+ def selector_matches?(selector)
42
+ selector.any? do |group|
43
+ group.keys.all? do |key|
44
+ input_has_key?(key) && (@input[key] == group[key] || group[key].nil?)
45
+ end
46
+ end
47
+ end
48
+
49
+ def input_has_key?(key)
50
+ @input.has_key?(key) && (@input[key] == true || !@input[key].empty?)
51
+ end
52
+
53
+ def priority_keys
54
+ @priority_keys ||= @priority_map.keys
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,54 @@
1
+ module Higml
2
+ def self.config
3
+ @config ||= Config.instance
4
+ end
5
+
6
+ class Config
7
+ include Singleton
8
+
9
+ # higml_directory should be a string
10
+ # global_pairs should be hash; every result is merged to it
11
+ OPTIONS = %w{higml_directory global_pairs config_directory}
12
+ attr_accessor *OPTIONS.collect{|o|o.to_sym}
13
+
14
+ def config_path
15
+ File.expand_path(File.join(self.config_directory, "higml-config.yml"))
16
+ end
17
+
18
+ def global_pairs
19
+ @global_pairs ||= {}
20
+ end
21
+
22
+ def set(config)
23
+ case config
24
+ when Hash: set_with_hash(config)
25
+ when IO: set_with_io(config)
26
+ when String: set_with_string(config)
27
+ end
28
+ end
29
+
30
+ def set_with_hash(config)
31
+ OPTIONS.each do |option|
32
+ self.send("#{option}=", config[option]) if config[option]
33
+ end
34
+ end
35
+
36
+ # String should be either a filename or YAML
37
+ def set_with_string(config)
38
+ if File.exists?(config)
39
+ set_with_yaml(File.read(config))
40
+ else
41
+ set_with_yaml(config)
42
+ end
43
+ end
44
+
45
+ def set_with_io(config)
46
+ set_with_hash(YAML.load(config))
47
+ config.close
48
+ end
49
+
50
+ def set_with_yaml(config)
51
+ set_with_hash(YAML.load(config))
52
+ end
53
+ end
54
+ end
data/lib/higml/node.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Higml
2
+ class Node
3
+ attr_accessor :selector, :children, :values
4
+ def initialize
5
+ self.values = []
6
+ self.children = []
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,115 @@
1
+ module Higml
2
+ class Parser
3
+ attr_accessor :source
4
+
5
+ def initialize(source)
6
+ @source = source
7
+ prepend_imports
8
+ end
9
+
10
+ def prepend_imports
11
+ already_imported = []
12
+ process_imports(@source, already_imported)
13
+ end
14
+
15
+ def process_imports(current_source, already_imported)
16
+ current_source.each_line do |line|
17
+ line = Line.new(line)
18
+ if line.type == :import
19
+ filename = line.to_import
20
+ next if already_imported.include?(filename)
21
+ already_imported << filename
22
+ new_source = File.read(File.join(Higml.config.higml_directory, filename))
23
+ @source = new_source + "\n" + @source
24
+ process_imports(new_source, already_imported)
25
+ else
26
+ break
27
+ end
28
+ end
29
+ end
30
+
31
+ def to_tree
32
+ current_node = Node.new
33
+ node_stack = [current_node]
34
+ indentation_level = 0
35
+
36
+ source.each_line do |line|
37
+ next if line.strip.empty?
38
+ line = Line.new(line)
39
+
40
+ case line.type
41
+ when :value
42
+ # TODO move this comment
43
+ # Every drop in indentation corresponds to a new node;
44
+ # It doesn't make sense to drop indentation level and
45
+ # define further values
46
+ current_node.values << line.to_value
47
+ when :selector
48
+ if line.indentation_level >= indentation_level
49
+ node_stack.push current_node
50
+ else
51
+ node_stack_to_pop = indentation_level - line.indentation_level - 1
52
+ node_stack.slice!(node_stack.size - node_stack_to_pop, node_stack.size)
53
+ end
54
+ current_node = Node.new
55
+ current_node.selector = line.to_selector
56
+ node_stack.last.children << current_node
57
+ else
58
+ next
59
+ end
60
+ indentation_level = line.indentation_level
61
+ end
62
+ node_stack[0]
63
+ end
64
+
65
+
66
+ class Line
67
+ VALUE_INDICATOR = 58
68
+ IMPORT_INDICATOR = 64
69
+ COMMENT_INDICATOR = 47
70
+
71
+ attr_reader :source, :stripped_source
72
+
73
+ def initialize(source)
74
+ @source = source
75
+ @stripped_source = source.strip
76
+ end
77
+
78
+ # Every two spaces is one indentation level
79
+ def indentation_level
80
+ spaces = (@source.size - @stripped_source.size)
81
+ spaces == 0 ? 0 : spaces / 2
82
+ end
83
+
84
+ def type
85
+ case @stripped_source[0]
86
+ when VALUE_INDICATOR: :value
87
+ when IMPORT_INDICATOR: :import
88
+ when COMMENT_INDICATOR: :comment
89
+ else
90
+ :selector
91
+ end
92
+ end
93
+
94
+ def to_selector
95
+ @stripped_source.split(",").collect do |group|
96
+ selector = {}
97
+ group = group.strip
98
+ group.split(" ").each do |pair|
99
+ key, value = pair.split(":")
100
+ selector[key.to_sym] = value || nil
101
+ end
102
+ selector
103
+ end
104
+ end
105
+
106
+ def to_value
107
+ Value.new(self)
108
+ end
109
+
110
+ def to_import
111
+ /@import (.*)/.match(@stripped_source)[1]
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,21 @@
1
+ module Higml
2
+ class Value
3
+ attr_accessor :type, :key, :raw_value
4
+
5
+ def initialize(line)
6
+ match = /:(.*?)(=?) (.*)$/.match(line.stripped_source)
7
+ @key = match[1].to_sym
8
+ @raw_value = match[3]
9
+ @type = match[2].empty? ? :static : :dynamic
10
+ end
11
+
12
+ def static?
13
+ @type == :static
14
+ end
15
+
16
+ def dynamic?
17
+ @type == :dynamic
18
+ end
19
+
20
+ end
21
+ end
data/lib/higml.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'singleton'
2
+ require 'yaml'
3
+ require 'higml/applier'
4
+ require 'higml/config'
5
+ require 'higml/node'
6
+ require 'higml/parser'
7
+ require 'higml/value'
8
+
9
+ module Higml
10
+ class << self
11
+ def values_for(input, selector_config, priority_map, mapper_context)
12
+ tree = tree_for_selector_config(selector_config)
13
+ Higml::Applier.new(input, tree, priority_map, mapper_context).result
14
+ end
15
+
16
+ def tree_for_selector_config(selector_config)
17
+ case selector_config
18
+ when String
19
+ possible_file_path = File.join(Higml.config.higml_directory, selector_config)
20
+ selector_config = File.read(possible_file_path) if File.exists?(possible_file_path)
21
+ Higml::Parser.new(selector_config).to_tree
22
+ when Higml::Node
23
+ selector_config
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1 @@
1
+ :applicationName WOO Application
@@ -0,0 +1,3 @@
1
+ higml_directory: dir
2
+ global_pairs:
3
+ :keywords: :chassis
@@ -0,0 +1,12 @@
1
+ / test comment
2
+ :channel Search
3
+
4
+ action:new
5
+ :pageName New Search
6
+
7
+ action:show
8
+ :pageName Search Results
9
+ :keywords= keywords
10
+
11
+ filter
12
+ :filter_terms= filter_terms
@@ -0,0 +1,2 @@
1
+ action:show filter, action:new filter
2
+ :filter filtered!
@@ -0,0 +1,2 @@
1
+ @import application.higml
2
+ :test yes
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "HIGML integration" do
4
+ before :each do
5
+ @input = {
6
+ :action => "show",
7
+ :filter => { :tags => "cat, shakespeare"}
8
+ }
9
+ @mapper_context = Context.new
10
+ end
11
+
12
+ it "should return the final values using input, higml filename, priority values" do
13
+ priority_map = {:keywords => "tongue paper"}
14
+ values = Higml.values_for(@input, 'search.higml', priority_map, @mapper_context)
15
+
16
+ values.should == {
17
+ :channel => "Search",
18
+ :pageName => "Search Results",
19
+ :keywords => priority_map[:keywords], # takes priority over @mapper_context.keywords
20
+ :filter_terms => @mapper_context.filter_terms
21
+ }
22
+ end
23
+
24
+ it "should allow you to use an existing tree instead of an sc filename" do
25
+ tree = Higml::Parser.new(File.read(File.join(Higml.config.higml_directory, 'search.higml'))).to_tree
26
+ values = Higml.values_for(@input, tree, {}, @mapper_context)
27
+
28
+ values.should == {
29
+ :channel => "Search",
30
+ :pageName => "Search Results",
31
+ :keywords => @mapper_context.keywords,
32
+ :filter_terms => @mapper_context.filter_terms
33
+ }
34
+ end
35
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Higml::Applier" do
4
+ it "should use a tree to build a result from input" do
5
+ tree = Higml::Parser.new(File.read(File.join(Higml.config.higml_directory, 'search.higml'))).to_tree
6
+
7
+ input = {
8
+ :action => "show",
9
+ :filter => { :tags => "cat, shakespeare"}
10
+ }
11
+
12
+ priority_map = {:keywords => "tongue paper"}
13
+ mapper_context = Context.new
14
+
15
+ values = Higml::Applier.new(input, tree, priority_map, mapper_context).result
16
+
17
+ values.should == {
18
+ :channel => "Search",
19
+ :pageName => "Search Results",
20
+ :keywords => priority_map[:keywords],
21
+ :filter_terms => mapper_context.filter_terms
22
+ }
23
+ end
24
+
25
+ it "should test all groups in a selector" do
26
+ tree = Higml::Parser.new(File.read(File.join(Higml.config.higml_directory, 'selectors_with_groups.higml'))).to_tree
27
+
28
+ input_group_1 = {
29
+ :action => "show",
30
+ :filter => { :tags => "cat, shakespeare"}
31
+ }
32
+
33
+ input_group_2 = {
34
+ :action => "new",
35
+ :filter => { :tags => "cat, shakespeare"}
36
+ }
37
+
38
+ priority_map = {}
39
+
40
+ mapper_context = Context.new
41
+ Higml::Applier.new(input_group_1, tree, priority_map, mapper_context).result.should == {:filter => "filtered!"}
42
+ Higml::Applier.new(input_group_2, tree, priority_map, mapper_context).result.should == {:filter => "filtered!"}
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Higml::Config" do
4
+ before :all do
5
+ Higml.config.config_directory = FIXTURE_DIRECTORY
6
+ end
7
+ before :each do
8
+ Higml.config.higml_directory = nil
9
+ Higml.config.global_pairs = nil
10
+ end
11
+
12
+ after :all do
13
+ Higml.config.higml_directory = FIXTURE_DIRECTORY
14
+ end
15
+
16
+ it "should set the config from a yaml filename" do
17
+ Higml.config.set(Higml.config.config_path)
18
+ Higml.config.higml_directory.should == "dir"
19
+ Higml.config.global_pairs.should == {:keywords => :chassis}
20
+ end
21
+
22
+ it "should set the config from a file" do
23
+ Higml.config.set(File.open(Higml.config.config_path))
24
+ Higml.config.higml_directory.should == "dir"
25
+ Higml.config.global_pairs.should == {:keywords => :chassis}
26
+ end
27
+
28
+ it "should set the config from a hash" do
29
+ Higml.config.set({
30
+ "higml_directory" => "a",
31
+ "global_pairs" => {:k => :v}
32
+ })
33
+ Higml.config.higml_directory.should == "a"
34
+ Higml.config.global_pairs.should == {:k => :v}
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Higml::Parser" do
4
+ it "should build a node tree from a properly formatted file" do
5
+ tree = Higml::Parser.new(File.read(File.join(Higml.config.higml_directory, 'search.higml'))).to_tree
6
+
7
+ tree.values[0].key.should == :channel
8
+ tree.values[0].raw_value.should == "Search"
9
+
10
+ tree.children[0].selector.should == [{:action => "new"}]
11
+ tree.children[0].values[0].key.should == :pageName
12
+ tree.children[0].values[0].raw_value.should == "New Search"
13
+
14
+ tree.children[1].selector.should == [{:action => "show"}]
15
+ tree.children[1].values[0].key.should == :pageName
16
+ tree.children[1].values[0].raw_value.should == "Search Results"
17
+ tree.children[1].values[0].type.should == :static
18
+
19
+ tree.children[1].values[1].key.should == :keywords
20
+ tree.children[1].values[1].raw_value.should == "keywords"
21
+ tree.children[1].values[1].type.should == :dynamic
22
+ end
23
+
24
+ it "should import values" do
25
+ tree = Higml::Parser.new(File.read(File.join(Higml.config.higml_directory, 'with_import.higml'))).to_tree
26
+ tree.values[0].key.should == :applicationName
27
+ tree.values[0].raw_value.should == "WOO Application"
28
+ tree.values[1].key.should == :test
29
+ tree.values[1].raw_value.should == "yes"
30
+ end
31
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --backtrace
@@ -0,0 +1,22 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'higml'
5
+ require 'spec'
6
+ require 'spec/autorun'
7
+
8
+ FIXTURE_DIRECTORY = File.join(File.dirname(__FILE__), 'fixtures')
9
+ Higml.config.higml_directory = FIXTURE_DIRECTORY
10
+
11
+ Spec::Runner.configure do |config|
12
+ end
13
+
14
+
15
+ class Context
16
+ def keywords
17
+ "juice mirror"
18
+ end
19
+ def filter_terms
20
+ "cat shakespeare"
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: higml
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 0
10
+ version: 0.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Daniel Higginbotham
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-23 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ type: :development
24
+ name: rspec
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 27
31
+ segments:
32
+ - 1
33
+ - 3
34
+ - 0
35
+ version: 1.3.0
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ prerelease: false
39
+ type: :development
40
+ name: bundler
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ hash: 23
47
+ segments:
48
+ - 1
49
+ - 0
50
+ - 0
51
+ version: 1.0.0
52
+ requirement: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ prerelease: false
55
+ type: :development
56
+ name: jeweler
57
+ version_requirements: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ hash: 7
63
+ segments:
64
+ - 1
65
+ - 5
66
+ - 2
67
+ version: 1.5.2
68
+ requirement: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ prerelease: false
71
+ type: :development
72
+ name: rcov
73
+ version_requirements: &id004 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ requirement: *id004
83
+ description: Higml is a terse format for converting a static input hash to a dynamic output hash.
84
+ email: daniel@flyingmachinestudios.com
85
+ executables: []
86
+
87
+ extensions: []
88
+
89
+ extra_rdoc_files:
90
+ - LICENSE.txt
91
+ - README.markdown
92
+ files:
93
+ - .document
94
+ - .rspec
95
+ - Gemfile
96
+ - Gemfile.lock
97
+ - LICENSE.txt
98
+ - README.markdown
99
+ - Rakefile
100
+ - VERSION
101
+ - examples/affiliations.higml
102
+ - examples/application.higml
103
+ - examples/articles.higml
104
+ - examples/contacts.higml
105
+ - examples/homes.higml
106
+ - examples/messages.higml
107
+ - examples/pages.higml
108
+ - examples/profiles.higml
109
+ - examples/searches.higml
110
+ - examples/simulate.higml
111
+ - higml.gemspec
112
+ - lib/higml.rb
113
+ - lib/higml/applier.rb
114
+ - lib/higml/config.rb
115
+ - lib/higml/node.rb
116
+ - lib/higml/parser.rb
117
+ - lib/higml/value.rb
118
+ - spec/fixtures/application.higml
119
+ - spec/fixtures/higml-config.yml
120
+ - spec/fixtures/search.higml
121
+ - spec/fixtures/selectors_with_groups.higml
122
+ - spec/fixtures/with_import.higml
123
+ - spec/higml_spec.rb
124
+ - spec/lib/higml/applier_spec.rb
125
+ - spec/lib/higml/config_spec.rb
126
+ - spec/lib/higml/parser_spec.rb
127
+ - spec/spec.opts
128
+ - spec/spec_helper.rb
129
+ has_rdoc: true
130
+ homepage: http://github.com/flyingmachine/higml
131
+ licenses:
132
+ - MIT
133
+ post_install_message:
134
+ rdoc_options: []
135
+
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 3
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ hash: 3
153
+ segments:
154
+ - 0
155
+ version: "0"
156
+ requirements: []
157
+
158
+ rubyforge_project:
159
+ rubygems_version: 1.3.7
160
+ signing_key:
161
+ specification_version: 3
162
+ summary: Higml is a terse format for converting an input hash to an output hash.
163
+ test_files:
164
+ - spec/higml_spec.rb
165
+ - spec/lib/higml/applier_spec.rb
166
+ - spec/lib/higml/config_spec.rb
167
+ - spec/lib/higml/parser_spec.rb
168
+ - spec/spec_helper.rb