pax_global_header00006660000000000000000000000064146533665610014531gustar00rootroot0000000000000052 comment=390a16b07cf05845a28b77128f293b78dbfec6e0 hirakuro-eim_xml-390a16b/000077500000000000000000000000001465336656100153345ustar00rootroot00000000000000hirakuro-eim_xml-390a16b/.gitignore000066400000000000000000000001011465336656100173140ustar00rootroot00000000000000/Gemfile.lock eim_xml-*.gem /bin /html /pkg /external /coverage hirakuro-eim_xml-390a16b/.rspec000066400000000000000000000000261465336656100164470ustar00rootroot00000000000000--require spec_helper hirakuro-eim_xml-390a16b/.rubocop.yml000066400000000000000000000002341465336656100176050ustar00rootroot00000000000000inherit_from: .rubocop_todo.yml require: - rubocop-rspec - rubocop-rake AllCops: NewCops: enable TargetRubyVersion: 3.2 Exclude: - 'bin/**' hirakuro-eim_xml-390a16b/.rubocop_todo.yml000066400000000000000000000064051465336656100206400ustar00rootroot00000000000000# This configuration was generated by # `rubocop --auto-gen-config` # on 2024-08-03 06:22:55 UTC using RuboCop version 1.28.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 1 # Configuration parameters: IgnoredMethods, CountRepeatedAttributes. Metrics/AbcSize: Max: 41 # Offense count: 25 # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. # IgnoredMethods: refine Metrics/BlockLength: Max: 334 # Offense count: 2 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: Max: 125 # Offense count: 1 # Configuration parameters: IgnoredMethods. Metrics/CyclomaticComplexity: Max: 20 # Offense count: 7 # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. Metrics/MethodLength: Max: 21 # Offense count: 3 # Configuration parameters: CountComments, CountAsOne. Metrics/ModuleLength: Max: 462 # Offense count: 1 # Configuration parameters: IgnoredMethods. Metrics/PerceivedComplexity: Max: 18 # Offense count: 42 # Configuration parameters: CountAsOne. RSpec/ExampleLength: Max: 84 # Offense count: 10 # Configuration parameters: . # SupportedStyles: have_received, receive RSpec/MessageSpies: EnforcedStyle: receive # Offense count: 1 RSpec/MultipleDescribes: Exclude: - 'spec/formatter_spec.rb' # Offense count: 82 RSpec/MultipleExpectations: Max: 33 # Offense count: 2 # Configuration parameters: AllowSubject. RSpec/MultipleMemoizedHelpers: Max: 7 # Offense count: 1 RSpec/NestedGroups: Max: 4 # Offense count: 3 RSpec/StubbedMock: Exclude: - 'spec/dsl_spec.rb' - 'spec/formatter_spec.rb' # Offense count: 5 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: Exclude: - 'spec/formatter_spec.rb' - 'spec/xhtml_spec.rb' # Offense count: 26 # Configuration parameters: AllowedConstants. Style/Documentation: Exclude: - 'spec/**/*' - 'test/**/*' - 'lib/eim_xml.rb' - 'lib/eim_xml/assertions.rb' - 'lib/eim_xml/dsl.rb' - 'lib/eim_xml/formatter.rb' - 'lib/eim_xml/formatter/element_wrapper.rb' - 'lib/eim_xml/matcher.rb' - 'lib/eim_xml/parser.rb' - 'lib/eim_xml/xhtml.rb' - 'lib/eim_xml/xhtml/dsl.rb' # Offense count: 20 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EnforcedStyle. # SupportedStyles: always, always_true, never Style/FrozenStringLiteralComment: Enabled: false # Offense count: 13 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EnforcedStyle. # SupportedStyles: literals, strict Style/MutableConstant: Exclude: - 'Rakefile' - 'lib/eim_xml.rb' - 'lib/eim_xml/parser.rb' - 'lib/eim_xml/xhtml.rb' # Offense count: 1 # This cop supports unsafe auto-correction (--auto-correct-all). # Configuration parameters: EnforcedStyle. # SupportedStyles: forbid_for_all_comparison_operators, forbid_for_equality_operators_only, require_for_all_comparison_operators, require_for_equality_operators_only Style/YodaCondition: Exclude: - 'lib/eim_xml/xhtml.rb' hirakuro-eim_xml-390a16b/.ruby-version000066400000000000000000000000061465336656100177750ustar00rootroot000000000000003.3.4 hirakuro-eim_xml-390a16b/Gemfile000066400000000000000000000005321465336656100166270ustar00rootroot00000000000000source 'http://rubygems.org' group :development do gem 'rake', '~> 13.2.1' gem 'rdoc', '~> 6.7.0' gem 'rspec', '~> 3.7' gem 'simplecov', '~> 0.22.0' gem 'rubocop', '~> 1.28' gem 'rubocop-rake', '~> 0.6.0' gem 'rubocop-rspec', '~> 3.0.3' gem 'guard', '~> 2.18' gem 'guard-rspec', '~> 4.7' gem 'guard-rubocop', '~> 1.5' end hirakuro-eim_xml-390a16b/Guardfile000066400000000000000000000032661465336656100171700ustar00rootroot00000000000000# A sample Guardfile # More info at https://github.com/guard/guard#readme ## Uncomment and set this to only include directories you want to watch # directories %w(app lib config test spec features) \ # .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")} ## Note: if you are using the `directories` clause above and you are not ## watching the project directory ('.'), then you will want to move ## the Guardfile to a watched dir and symlink it back, e.g. # # $ mkdir config # $ mv Guardfile config/ # $ ln -s config/Guardfile . # # and, you'll have to watch "config/Guardfile" instead of "Guardfile" # NOTE: The cmd option is now required due to the increasing number of ways # rspec may be run, below are examples of the most common uses. # * bundler: 'bundle exec rspec' # * bundler binstubs: 'bin/rspec' # * spring: 'bin/rspec' (This will use spring if running and you have # installed the spring binstubs per the docs) # * zeus: 'zeus rspec' (requires the server to be started separately) # * 'just' rspec: 'rspec' group :red_green_refactor, halt_on_fail: true do guard :rspec, cmd: 'bundle exec rspec' do require 'guard/rspec/dsl' dsl = Guard::RSpec::Dsl.new(self) # Feel free to open issues for suggestions and improvements # RSpec files rspec = dsl.rspec watch(rspec.spec_helper) { rspec.spec_dir } watch(rspec.spec_support) { rspec.spec_dir } watch(rspec.spec_files) # Ruby files ruby = dsl.ruby dsl.watch_spec_files_for(ruby.lib_files) end guard :rubocop, all_on_start: false do watch(/.+\.rb$/) watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) } end end hirakuro-eim_xml-390a16b/LICENSE000066400000000000000000000432541465336656100163510ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. hirakuro-eim_xml-390a16b/README000066400000000000000000000023071465336656100162160ustar00rootroot00000000000000= Easy IMplemented XML :lang:ja Easy IMplemented XML(EimXML)は、RubyスクリプトからXMLを作成するためのライブラリです。 動作が軽くなるように、単純さを心がけて実装しています。 :lang:en Easy IMplemented XML(EimXML) is library to construct XML on Ruby. For light weight performance, this library is implemented simply. :lang: = URLs * Document(Japanese)[http://eimxml.rubyforge.org/ja/] * Document(English)[http://eimxml.rubyforge.org/en/] * MercurialRepository[https://hg.hinet.mydns.jp/eim_xml/] = Sample :lang:ja 例えば、次のようなHTMLを作成する場合は :lang:en For example, to construct html like bellow :lang: TITLE

Texts...

:lang:ja スクリプトは以下のように記述します。 :lang:en write script like bellow. :lang: #!/usr/bin/ruby # require "rubygems" require "eim_xml/xhtml" include EimXML::XHTML html = HTML.new do |html| html << Head.new do |head| head << Title.new do |title| title << "TITLE" end end html << Body.new do |body| body << P.new do |par| par << "Text..." end end end html.write($stdout, false) hirakuro-eim_xml-390a16b/Rakefile000066400000000000000000000014041465336656100170000ustar00rootroot00000000000000require 'rdoc/task' require 'rspec/core/rake_task' Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.options << '-S' rdoc.options << '-w' << '3' rdoc.options << '-c' << 'UTF-8' rdoc.rdoc_files.include('lib/**/*.rb') rdoc.title = 'Easy IMplemented XML' rdoc.main = 'README' rdoc.rdoc_files.include(FileList['lib/**/*.rb', 'README']) end RSpec::Core::RakeTask.new do |s| s.rspec_opts ||= [] s.rspec_opts << '-c' end namespace :spec do RSpec::Core::RakeTask.new(:coverage) do |s| s.rspec_opts ||= [] s.rspec_opts << '-c' s.rspec_opts << '-r' << './spec/helper_coverage' end RSpec::Core::RakeTask.new(:profile) do |s| s.verbose = false s.rspec_opts ||= [] s.rspec_opts << '-c' s.rspec_opts << '-p' end end task default: :spec hirakuro-eim_xml-390a16b/eim_xml.gemspec000066400000000000000000000006401465336656100203330ustar00rootroot00000000000000# frozen_string_literal: true Gem::Specification.new do |s| s.name = 'eim_xml' s.version = '1.0.0' s.summary = 'Easy IMplemented XML' s.author = 'KURODA Hiraku' s.email = 'hirakuro@gmail.com' s.homepage = 'https://github.com/hirakuro/eim_xml' s.license = 'GPL-2.0-only' s.metadata['rubygems_mfa_required'] = 'true' s.required_ruby_version = '>= 3.2.0' s.files = Dir['LICENSE', 'lib/**/*'] end hirakuro-eim_xml-390a16b/index.html000066400000000000000000000010361465336656100173310ustar00rootroot00000000000000 Easy IMplemented XML Index

Documents for Easy IMplemented XML

hirakuro-eim_xml-390a16b/lib/000077500000000000000000000000001465336656100161025ustar00rootroot00000000000000hirakuro-eim_xml-390a16b/lib/eim_xml.rb000066400000000000000000000111401465336656100200560ustar00rootroot00000000000000# Easy IMplementation of XML # # Copyright (C) 2006, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. # module EimXML XML_DECLARATION = %() class PCString attr_reader :encoded_string, :src alias to_s encoded_string ENCODING_MAP = { '&' => '&', '"' => '"', "'" => ''', '<' => '<', '>' => '>' } def self.encode(src) src.to_s.gsub(/[&"'<>]/) do |m| ENCODING_MAP[m] end end def self.[](obj) obj.is_a?(PCString) ? obj : PCString.new(obj) end def initialize(src, encoded = false) # rubocop:disable Style/OptionalBooleanParameter @src = src @encoded_string = encoded ? src : PCString.encode(src) end def ==(other) other.is_a?(PCString) ? @encoded_string == other.encoded_string : self == PCString.new(other) end def write_to(out = '') out << encoded_string end end class Comment def initialize(text) raise ArgumentError, "Can not include '--'" if text =~ /--/ @text = text end def write_to(out = '') out << "" end end class Element attr_reader :name, :attributes, :contents NEST = ' ' def initialize(name, attributes = {}) @name = name.to_sym @attributes = {} @contents = [] attributes.each do |k, v| @attributes[k.to_sym] = v end yield(self) if block_given? end def name=(new_name) @name = new_name.to_sym end protected :name= def add(content) case content when nil # nothing to do when Array content.each { |i| add(i) } else @contents << content end self end alias << add def name_and_attributes(out = '') out << @name.to_s @attributes.each do |k, v| next unless v out << " #{k}='#{v.is_a?(PCString) ? v : PCString.encode(v.to_s)}'" end end def write_to(out = '') out << '<' name_and_attributes(out) if @contents.empty? out << ' />' else out << '>' @contents.each do |c| case c when Element c.write_to(out) when PCString out << c.to_s else out << PCString.encode(c.to_s) end end out << "" end out end alias to_s write_to alias inspect to_s def ==(other) return false unless other.is_a?(Element) @name == other.name && @attributes == other.attributes && @contents == other.contents end def add_attribute(key, value) @attributes[key.to_sym] = value end alias []= add_attribute def [](key) if key.is_a?(Integer) @contents[key] else @attributes[key.to_sym] end end def del_attribute(key) @attributes.delete(key.to_sym) end def pcstring_contents @contents.select { |c| c.is_a?(String) || c.is_a?(PCString) }.map { |c| c.is_a?(String) ? PCString.new(c) : c } end def match(obj, attr = nil) return match(Element.new(obj, attr)) if attr return obj =~ @name.to_s if obj.is_a?(Regexp) return @name == obj if obj.is_a?(Symbol) return is_a?(obj) if obj.is_a?(Module) raise ArgumentError unless obj.is_a?(Element) return false unless @name == obj.name obj.attributes.all? do |k, v| (v.nil? && !@attributes.include?(k)) || (@attributes.include?(k) && (v.is_a?(Regexp) ? v =~ @attributes[k] : PCString[v] == PCString[@attributes[k]])) end and obj.contents.all? do |i| case i when Element has_element?(i) when String pcstring_contents.include?(PCString.new(i)) when PCString pcstring_contents.include?(i) when Regexp @contents.any? { |c| c.is_a?(String) and i =~ c } end end end alias =~ match def has?(obj, attr = nil) return has?(Element.new(obj, attr)) if attr @contents.any? do |i| if i.is_a?(Element) i.match(obj) || i.has?(obj) else obj.is_a?(Module) && i.is_a?(obj) end end end alias has_element? has? alias include? has? def find(obj, dst = Element.new(:found)) return find(Element.new(obj, dst)) if dst.is_a?(Hash) dst << self if match(obj) @contents.each do |i| if i.is_a?(Element) i.find(obj, dst) elsif obj.is_a?(Module) && i.is_a?(obj) dst << i end end dst end end end hirakuro-eim_xml-390a16b/lib/eim_xml/000077500000000000000000000000001465336656100175345ustar00rootroot00000000000000hirakuro-eim_xml-390a16b/lib/eim_xml/assertions.rb000066400000000000000000000007261465336656100222600ustar00rootroot00000000000000require 'eim_xml' module EimXML module Assertions def assert_has(expect, element, message = '') message << "\n" unless message.empty? message << "<#{element}> doesn't have\n<#{expect.inspect}>" assert_block(message) do element.has?(expect) end rescue Test::Unit::AssertionFailedError => e bt = e.backtrace.grep_v(/#{Regexp.escape(__FILE__)}/) raise Test::Unit::AssertionFailedError, e.message, bt end end end hirakuro-eim_xml-390a16b/lib/eim_xml/dsl.rb000066400000000000000000000053411465336656100206460ustar00rootroot00000000000000# Easy IMplementation of XML # # Copyright (C) 2006,2008, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. # require 'eim_xml' module EimXML class BaseDSL def add(content) @_container << content end alias << add def import_variables(src) src.instance_variables.each do |v| instance_variable_set(v, src.instance_variable_get(v)) unless v =~ /\A@_[^_]/ end self end def _build(klass, *arg, &proc) e = klass.new(*arg) @_container << e if @_container if proc oc = @_container @_container = e begin instance_eval(&proc) ensure @_container = oc end end e end private :_build def _push(container) oc = @_container @_container = container begin yield if block_given? container ensure @_container = oc end end private :_push def self.register(*args) args.each do |klass, name| name ||= klass.name.downcase[/(?:.*::)?(.*)$/, 1] # rubocop:disable Security/Eval, Layout/LineLength eval("def #{name}(*a, &p);_build(#{klass}, *a, &p);end", binding, __FILE__, __LINE__) # def element(*a, &p);_build(Element, *a, &p);end eval("def self.#{name}(*a, &p);new.#{name}(*a, &p);end", binding, __FILE__, __LINE__) # def self.element(*a, &p);new.element(*a, &p);end # rubocop:enable Security/Eval, Layout/LineLength end end end class DSL < BaseDSL end class OpenDSL def _build(klass, *arg, &proc) e = klass.new(*arg) oc = @_container oc << e if oc.is_a?(Element) @_container = e begin proc&.call(self) e ensure @_container = oc end end private :_build def self.register_base(_dsl, binding, *args) args.each do |klass, name| name ||= klass.name.downcase[/(?:.*::)?(.*)$/, 1] # rubocop:disable Security/Eval, Layout/LineLength eval("def #{name}(*a, &p);_build(#{klass}, *a, &p);end", binding, __FILE__, __LINE__) # def element(*a, &p);_build(Element, *a, &p);end eval("def self.#{name}(*a, &p);self.new.#{name}(*a, &p);end", binding, __FILE__, __LINE__) # def self.element(*a, &p);self.new.element(*a, &p);end # rubocop:enable Security/Eval, Layout/LineLength end end def self.register(*) register_base(self, binding, *) end def initialize @_container = nil yield(self) if block_given? end def add(content) @_container.add(content) end alias << add def container @_container end end DSL.register Element, Comment OpenDSL.register Element, Comment end hirakuro-eim_xml-390a16b/lib/eim_xml/formatter.rb000066400000000000000000000045041465336656100220670ustar00rootroot00000000000000require 'eim_xml' module EimXML class Formatter attr_reader :out def self.write(element, opt = {}) opt = { out: '' }.merge(opt) new(opt).write(element) opt[:out] end def initialize(opt) @out = opt[:out] @preservers = opt[:preservers] @preserve_space = false @indent_string = ' ' @indent_depth = 0 @option = opt.dup.tap { |h| %i[out preservers].each { |k| h.delete(k) } } end def write(src) case src when ElementWrapper write_wrapper(src) when Comment write_comment(src) when Element write_element(src) when PCString write_pcstring(src) else write_string(src.to_s) end end def indent(&proc) @indent_depth += 1 proc.call ensure @indent_depth -= 1 end def preserve_space_element?(elm) @preservers&.any? do |e| case e when Symbol e == elm.name when Class elm.is_a?(e) end end end def write_indent out << (@indent_string * @indent_depth) unless @preserve_space end def write_newline out << "\n" unless @preserve_space end def write_comment(commend) write_indent commend.write_to(out) write_newline end def write_contents_of(elm) flag = @preserve_space @preserve_space = true if preserve_space_element?(elm) write_newline indent do elm.contents.each do |c| write(c) end end write_indent ensure @preserve_space = flag end def write_element(elm) write_indent out << '<' elm.name_and_attributes(out) case elm.contents.size when 0 out << ' />' else out << '>' write_contents_of(elm) out << "" end write_newline end def write_pcstring(pcs) pcs.encoded_string.each_line do |l| write_indent out << l end write_newline end def write_string(str) PCString.encode(str).each_line do |l| write_indent out << l end write_newline end def write_wrapper(wrapper) wrapper.each(@option) do |i| write(i) end end end end require 'eim_xml/formatter/element_wrapper' hirakuro-eim_xml-390a16b/lib/eim_xml/formatter/000077500000000000000000000000001465336656100215375ustar00rootroot00000000000000hirakuro-eim_xml-390a16b/lib/eim_xml/formatter/element_wrapper.rb000066400000000000000000000002221465336656100252510ustar00rootroot00000000000000module EimXML class Formatter class ElementWrapper def each(option, &) contents(**option).each(&) end end end end hirakuro-eim_xml-390a16b/lib/eim_xml/matcher.rb000066400000000000000000000010451465336656100215040ustar00rootroot00000000000000require 'eim_xml' module EimXML module Matchers class HaveContent def initialize(expected) @expected = expected end def matches?(target) @target = target @target.has?(@expected) end def failure_message "expected #{@target.inspect} must have #{@expected}, but not." end def negative_failure_message "expected #{@target.inspect} must not have #{@expected}, but has." end end def have(expected) HaveContent.new(expected) end end end hirakuro-eim_xml-390a16b/lib/eim_xml/parser.rb000066400000000000000000000033441465336656100213610ustar00rootroot00000000000000# XML parser for EimXML # # Copyright (C) 2006, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. # require 'eim_xml' require 'strscan' module EimXML class ParseError < StandardError end class Parser attr_reader :scanner module RE EMPTY_ELEMENT = %r{<([^>]*?)/>} START_TAG = %r{<([^>]*?([^/>]\s*))>} END_TAG = %r{} ATTRIBUTE = /\s+([^=\s]+)\s*=\s*('(.*?)'|"(.*?)")/m STRING = /[^<]+/ end PARSING_MAP = { 'amp' => '&', 'quot' => '"', 'apos' => "'", 'lt' => '<', 'gt' => '>' } def initialize(src) @scanner = StringScanner.new(src) @scanner.scan(/\s*<\?.*?\?>\s*/) end def parse if @scanner.scan(RE::EMPTY_ELEMENT) parse_empty_element elsif @scanner.scan(RE::START_TAG) parse_start_tag elsif @scanner.scan(RE::STRING) parse_string end end def parse_tag s = StringScanner.new(@scanner[1]) e = Element.new(s.scan(/\S+/)) e[s[1]] = s[3] || s[4] while s.scan(RE::ATTRIBUTE) e end protected :parse_tag def parse_empty_element parse_tag end protected :parse_empty_element def parse_start_tag e = parse_tag until @scanner.scan(RE::END_TAG) c = parse raise ParseError, 'Syntax error.' unless c e << c end raise ParseError, 'End tag mismatched.' unless @scanner[1].to_sym == e.name e end protected :parse_start_tag def parse_string s = @scanner[0] s = s.gsub(/&(amp|quot|apos|lt|gt);/) do PARSING_MAP[Regexp.last_match(1)] end PCString.new(s) end protected :parse_string end end hirakuro-eim_xml-390a16b/lib/eim_xml/xhtml.rb000066400000000000000000000073771465336656100212330ustar00rootroot00000000000000require 'English' require 'eim_xml' require 'eim_xml/formatter' module EimXML module XHTML module DocType XHTML_MATHML = %() end class Base < EimXML::Element end class HTML < Base attr_accessor :prefix module NameSpace XHTML = 'http://www.w3.org/1999/xhtml' end def initialize(attributes = {}) super(:html, attributes) end def write_to(out = '') out << @prefix << "\n" if @prefix super end end class Simple < Base def initialize(attributes = {}) super(self.class.name[/.*::(.*)/, 1].downcase.to_sym, attributes) end end class PreserveSpace < Base def initialize(name = {}, attributes = {}) if name.is_a?(Hash) super(self.class.name[/.*::(.*)/, 1].downcase.to_sym, name) else super end end end class HEAD < Simple; end class META < Simple; end class LINK < Simple; end class IMG < Simple; end class STYLE < PreserveSpace; end class SCRIPT < PreserveSpace; end class TITLE < Simple; end class BODY < Simple; end class PRE < PreserveSpace; end class FORM < Simple def initialize(attributes = {}) if attributes && (s = attributes.delete(:session)) name = attributes.delete(:session_name) || 'token' require 'digest/sha1' token = s[name] ||= Digest::SHA1.hexdigest("#{$PID}#{Time.now}#{rand}") end super add(HIDDEN.new(name:, value: token)) if token end end class H1 < PreserveSpace; end class H2 < PreserveSpace; end class H3 < PreserveSpace; end class H4 < PreserveSpace; end class H5 < PreserveSpace; end class H6 < PreserveSpace; end class P < PreserveSpace; end class A < PreserveSpace; end class EM < PreserveSpace; end class STRONG < PreserveSpace; end class DIV < Simple; end class SPAN < PreserveSpace; end class UL < Simple; end class OL < Simple; end class LI < PreserveSpace; end class DL < Simple; end class DT < PreserveSpace; end class DD < PreserveSpace; end class TABLE < Simple; end class CAPTION < PreserveSpace; end class TR < Simple; end class TH < PreserveSpace; end class TD < PreserveSpace; end class BR < Simple; end class HR < Simple; end class SELECT < Simple; end class OPTION < Simple; end module Hn def self.new(level, attr = {}, &) raise ArgumentError unless 1 <= level && level <= 6 klass = EimXML::XHTML.const_get("H#{level}") klass.new(attr, &) end end class TEXTAREA < PreserveSpace; end class INPUT < Base def initialize(opt = {}) super(:input, opt) end end class BUTTON < PreserveSpace def initialize(opt = {}) super(:button, opt) end end class SUBMIT < BUTTON def initialize(opt = {}) super(opt.merge(type: :submit)) end end class HIDDEN < INPUT def initialize(opt = {}) super(opt.merge(type: :hidden)) end end class TEXT < INPUT def initialize(opt = {}) super(opt.merge(type: :text)) end end class PASSWORD < INPUT def initialize(opt = {}) super(opt.merge(type: :password)) end end class FILE < INPUT def initialize(opt = {}) super(opt.merge(type: :file)) end end PRESERVE_SPACES = [PreserveSpace] class Formatter < EimXML::Formatter def self.write(element, opt = {}) EimXML::Formatter.write(element, **opt.merge(preservers: PRESERVE_SPACES)) end end end end hirakuro-eim_xml-390a16b/lib/eim_xml/xhtml/000077500000000000000000000000001465336656100206705ustar00rootroot00000000000000hirakuro-eim_xml-390a16b/lib/eim_xml/xhtml/dsl.rb000066400000000000000000000005131465336656100217760ustar00rootroot00000000000000require 'eim_xml/dsl' require 'eim_xml/xhtml' module EimXML module XHTML class DSL < EimXML::BaseDSL end class OpenDSL < EimXML::OpenDSL end constants.each do |c| v = const_get(c) if v.is_a?(Class) && /_$/ !~ v.name DSL.register v OpenDSL.register v end end end end hirakuro-eim_xml-390a16b/spec/000077500000000000000000000000001465336656100162665ustar00rootroot00000000000000hirakuro-eim_xml-390a16b/spec/assertions_test.rb000066400000000000000000000013141465336656100220430ustar00rootroot00000000000000# Test for eim_xml/assertions.rb # # Copyright (C) 2006, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. $LOAD_PATH.unshift "#{File.dirname(File.expand_path(__FILE__), 2)}/lib" require 'test/unit' require 'eim_xml/assertions' class EimXMLAssertionsTest < Test::Unit::TestCase include EimXML include EimXML::Assertions def test_assert_has e = Element.new(:tag) do |tag| tag << Element.new(:sub) end assert_nothing_raised do assert_has(:sub, e) end a = assert_raises(Test::Unit::AssertionFailedError) do assert_has(:no, e) end assert(a.backtrace.none? do |i| i =~ %r{eim_xml/assertions\.rb} end) end end hirakuro-eim_xml-390a16b/spec/dsl_spec.rb000066400000000000000000000134301465336656100204100ustar00rootroot00000000000000require 'eim_xml/dsl' module Module.new::M # rubocop:disable Style/ClassAndModuleChildren include EimXML EDSL = EimXML::DSL describe EimXML::DSL do it 'scope is in instance of DSL' do outer = inner = nil e3 = e2 = nil block_executed = false e = EDSL.element(:out, k1: 'v1') do outer = self e2 = element(:in, k2: 'v2') do block_executed = true inner = self e3 = element(:deep) end end expect(block_executed).to be(true) expect(outer).to be_a(EDSL) expect(inner).to be_a(EDSL) expect(outer).to equal(inner) expect(e.name).to eq(:out) expect(e[:k1]).to eq('v1') expect(e[0].name).to eq(:in) expect(e[0][:k2]).to eq('v2') expect(e[0][0].name).to eq(:deep) expect(e2).to equal(e[0]) expect(e3).to equal(e[0][0]) end it '#comment' do expect(Comment).to receive(:new).with('comment').and_return(:success) expect(EDSL.comment('comment')).to eq(:success) end it '#import_variables' do d = EDSL.new o = Object.new o.instance_variable_set('@v1', 1) o.instance_variable_set('@v2', '2') o.instance_variable_set('@_v3', :t) o.instance_variable_set('@__v4', 4) o.instance_variable_set('@_container', :t) orig_c = d.instance_variable_get('@_container') expect(d.import_variables(o)).to equal(d) expect(d.instance_variable_get('@_container')).to eq(orig_c) expect(d.instance_variables.map(&:to_s).sort).to eq(['@v1', '@v2', '@__v4'].sort) expect(d.instance_variable_get('@v1')).to eq(1) expect(d.instance_variable_get('@v2')).to eq('2') expect(d.instance_variable_get('@__v4')).to eq(4) end describe '#_push' do before do @dsl = Class.new(EimXML::DSL) do def call_push(content) _push(content) do element(:e) end end def exec element(:e) do element(:f) end end end end it 'returns given container' do a = [] expect(@dsl.new.call_push(a)).to equal(a) expect(a).to eq([EimXML::Element.new(:e)]) expect(@dsl.new.exec).to eq(EimXML::Element.new(:e).add(EimXML::Element.new(:f))) end end end describe 'Subclass of BaseDSL' do let(:dsl1) do Class.new(EimXML::BaseDSL) do register([EimXML::Element, 'call']) register(Hash) register(String, Array, Object) end end it 'register' do expect { EDSL.call(:dummy) }.to raise_error(NoMethodError) expect { BaseDSL.call(:dummy) }.to raise_error(NoMethodError) expect { dsl1.element(:dummy) }.to raise_error(NoMethodError) expect(dsl1.call(:dummy)).to be_a(Element) expect(dsl1.hash).to be_a(Hash) expect(dsl1.string).to be_a(String) expect(dsl1.array).to be_a(Array) expect(dsl1.object).to be_a(Object) end end describe EimXML::OpenDSL do it 'scope of block is one of outside' do @scope_checker_variable = 1 block_executed = false OpenDSL.new do |dsl| block_executed = true expect(dsl).to be_a(OpenDSL) expect(dsl.container).to be_nil dsl.element(:base, key1: 'v1') do expect(@scope_checker_variable).to eq(1) expect(self).not_to be_a(Element) expect(dsl.container).to be_a(Element) expect(dsl.container).to eq(Element.new(:base, key1: 'v1')) dsl.element(:sub, key2: 'v2') do expect(dsl.container).to be_a(Element) expect(dsl.container).to eq(Element.new(:sub, key2: 'v2')) end expect(dsl.element(:sub2)).to eq(Element.new(:sub2)) end end expect(block_executed).to be true end it 'DSL methods return element' do d = OpenDSL.new expect(d.container).to be_nil r = d.element(:base, key1: 'v1') do d.element(:sub, key2: 'v2') end expect(r).to eq(EDSL.element(:base, key1: 'v1') do element(:sub, key2: 'v2') end) end it "DSL method's block given instance of OpenDSL" do e = OpenDSL.new.element(:base) do |d| expect(d).to be_a(OpenDSL) expect(d.container.name).to eq(:base) d.element(:sub) do |d2| expect(d2).to equal(d) end end expect(e).to eq(EDSL.element(:base) do element(:sub) end) end it 'ensure reset container when error raised' do OpenDSL.new do |d| d.element(:base) do d.element(:sub) do raise 'OK' end rescue RuntimeError => e raise unless e.message == 'OK' expect(d.container.name).to eq(:base) raise end rescue RuntimeError => e raise unless e.message == 'OK' expect(d.container).to be_nil end end it 'respond to add' do r = OpenDSL.new.element(:base) do |d| d.add 'text' d.element(:sub) do s = Element.new(:sub) s.add('sub text') expect(d.add('sub text')).to eq(s) end end expect(r).to eq(EDSL.element(:base) do add 'text' element(:sub) do add 'sub text' end end) end it 'respond to <<' do r = OpenDSL.new.element(:base) do |d| b = Element.new(:base) b << 'text' << 'next' expect(d << 'text' << 'next').to eq(b) end expect(r).to eq(EDSL.element(:base) do add 'text' add 'next' end) end it 'can call directly element method' do r = OpenDSL.element(:base) do |d| d.element(:sub) d.element(:sub2) end expect(r).to eq(EDSL.element(:base) do element(:sub) element(:sub2) end) end end end hirakuro-eim_xml-390a16b/spec/eim_xml_spec.rb000066400000000000000000000353431465336656100212670ustar00rootroot00000000000000require 'eim_xml/dsl' module Module.new::M # rubocop:disable Style/ClassAndModuleChildren include EimXML EDSL = EimXML::DSL describe PCString do it '.encode' do expect(described_class.encode("<>\"'&")).to eq('<>"'&') expect(described_class.encode('&test;')).to eq('&test;') expect(described_class.encode('&')).to eq('&amp;') expect(described_class.encode(:'sym&')).to eq('sym&') end it '.new' do expect(described_class.new('&').encoded_string).to eq('&') expect(described_class.new('&', true).encoded_string).to eq('&') pcs = described_class.new(:'sym&') expect(pcs.encoded_string).to eq('sym&') expect(pcs.src).to eq(:'sym&') end describe '.[]' do it 'returns itself when given object is a PCString' do pcs = described_class.new('s') expect(described_class[pcs]).to equal(pcs) end it 'returns PCString.new(obj) if given obj is not a PCString' do o = 'str' r = described_class[o] r.is_a?(EimXML::PCString) expect(r.src).to eq(o) end end it '#==' do # rubocop:disable RSpec/IdenticalEqualityAssertion expect(described_class.new('str')).to eq(described_class.new('str')) expect(described_class.new('&')).to eq('&') expect(described_class.new('&', true)).not_to eq('&') expect(described_class.new('&', true)).to eq(described_class.new('&', true)) expect(described_class.new('&')).to eq(described_class.new('&', true)) # rubocop:enable RSpec/IdenticalEqualityAssertion end describe '#write_to' do before do @pc = described_class.new('&') end it 'returns encoded string' do expect(@pc.write_to).to eq('&amp;') end it 'returns given destination' do s = '' expect(@pc.write_to(s)).to equal(s) end end end describe Comment do it ".new should raise error if given string include '--'" do expect { described_class.new('--') }.to raise_error(ArgumentError) end describe '#write_to' do it 'returns comment with markup' do expect(described_class.new('flat comment').write_to).to eq('') expect(described_class.new("multi-line\ncomment").write_to).to eq("") expect(described_class.new('&').write_to).to eq('') end it 'returns given destination' do s = '' expect(described_class.new('dummy').write_to(s)).to equal(s) end end end describe Element do let(:dummy_class) do Class.new(Element) do def chgname(name) self.name = name end end end it '#name' do e = described_class.new('el') expect(e.name).to eq(:el) expect { e.name = 'changed' }.to raise_error(NoMethodError) d = dummy_class.new('el1') expect(d.name).to eq(:el1) d.chgname(:el2) expect(d.name).to eq(:el2) d.chgname('el3') expect(d.name).to eq(:el3) end it '#attributes should return hash whose keys are Symbol' do e = described_class.new('el', 'a1' => 'v1', :a2 => 'v2', 'a3' => nil) expect(e.name).to eq(:el) expect(e.attributes).to eq({ a1: 'v1', a2: 'v2', a3: nil }) end it '#[]' do e = described_class.new(:el, attr: 'value') e << 'test' expect(e[:attr]).to eq('value') expect(e[0]).to eq('test') end it '#add_attribute' do e = described_class.new('el') e.add_attribute('key_str', 'value1') e.add_attribute(:key_sym, 'value2') expect(e.attributes).to eq({ key_str: 'value1', key_sym: 'value2' }) e.add_attribute(:nil, nil) expect(e.attributes).to eq({ key_str: 'value1', key_sym: 'value2', nil: nil }) end it '#del_attribute' do e = described_class.new('el', { a1: 'v1', a2: 'v2' }) e.del_attribute('a1') expect(e.attributes).to eq({ a2: 'v2' }) e.del_attribute(:a2) expect(e.attributes).to eq({}) end it '#contents' do sub = described_class.new('sub') e = described_class.new('el') << 'String1' << 'String2' << sub expect(e.contents).to eq(['String1', 'String2', sub]) end it '#add' do e = described_class.new('el').add(described_class.new('sub')) expect(e).to be_a(described_class) expect(e.name).to eq(:el) e = described_class.new('el') e.add(described_class.new('sub1')) e.add([described_class.new('sub2').add('text'), 'string']) expect(e.contents).to eq([described_class.new('sub1'), described_class.new('sub2').add('text'), 'string']) e = described_class.new('el') e.add(nil) expect(e.contents.size).to eq(0) e = described_class.new('el').add(:symbol) expect(e.contents).to eq([:symbol]) expect(e.to_s).to eq('symbol') e = described_class.new('super') << described_class.new('sub') expect(e.name).to eq(:super) expect(e.contents).to eq([described_class.new('sub')]) end describe '#write_to' do it 'returns flatten string' do expect(described_class.new('e').write_to).to eq('') e = described_class.new('super') e << described_class.new('sub') expect(e.write_to).to eq('') e << described_class.new('sub2') expect(e.write_to).to eq('') e = described_class.new('super') << 'content1' s = described_class.new('sub') s << 'content2' e << s expect(e.write_to).to eq('content1content2') e = described_class.new('el') e.attributes['a1'] = 'v1' e.attributes['a2'] = "'\"<>&" s = e.write_to expect(s).to match(%r{\A]*) />\z}) expect(s).to match(/a1='v1'/) expect(s).to match(/a2=''"<>&'/) end it 'returns string without attribute whose value is nil or false' do s = EimXML::Element.new('e', attr1: '1', attr2: true, attr3: nil, attr4: false).write_to re = %r{\A\z} expect(s).to match(re) s =~ %r{\A\z} expect([[Regexp.last_match(1), Regexp.last_match(2)], [Regexp.last_match(3), Regexp.last_match(4)]].sort) .to eq([%w[1 1], %w[2 true]]) end it 'returns same string whenever name of element given with string or symbol' do sym = described_class.new(:tag, attr: 'value') str_name = described_class.new('tag', attr: 'value') str_attr = described_class.new(:tag, 'attr' => 'value') expect(str_name.write_to).to eq(sym.write_to) expect(str_attr.write_to).to eq(sym.write_to) end end it 'encode special characters' do e = described_class.new('el') << "&\"'<>" e << PCString.new("&\"'<>", true) e.attributes['key'] = PCString.new("&\"'<>", true) expect(e.to_s).to eq(%('>&"'<>&"'<>)) end it '#dup' do e = described_class.new('el') e.attributes['key'] = 'value' e << 'String' e << 'Freeze'.freeze s = described_class.new('sub') s.attributes['subkey'] = 'subvalue' e << s f = e.dup expect(f.attributes.object_id).to eq(e.attributes.object_id) expect(f.contents.object_id).to eq(e.contents.object_id) expect(f.to_s).to eq(e.to_s) end it '#clone' do e = described_class.new('el') e.attributes['key'] = 'value' e << 'String' e << 'Freeze'.freeze s = described_class.new('sub') s.attributes['subkey'] = 'subvalue' e << s f = e.clone expect(f.attributes.object_id).to eq(e.attributes.object_id) expect(f.contents.object_id).to eq(e.contents.object_id) expect(f.to_s).to eq(e.to_s) end it '#==' do e1 = described_class.new('el') e1.attributes['key'] = 'value' s = described_class.new('sub') s << 'String' e1 << s e2 = e1.dup expect(e2).to eq(e1) e3 = described_class.new('e') e3.attributes['key'] = 'value' s = described_class.new('sub') s << 'String' e3 << s expect(e3).not_to eq(e1) e3 = described_class.new('e') e3.attributes['k'] = 'value' s = described_class.new('sub') s << 'String' e3 << s expect(e3).not_to eq(e1) e3 = described_class.new('e') e3.attributes['key'] = 'v' s = described_class.new('sub') s << 'String' e3 << s expect(e3).not_to eq(e1) e3 = described_class.new('e') e3.attributes['key'] = 'value' s = described_class.new('sub') s << 'S' e3 << s expect(e3).not_to eq(e1) e3 = described_class.new('e') e3.attributes['key'] = 'value' s = described_class.new('s') s << 'String' e3 << s expect(e3).not_to eq(e1) end describe '.new' do it 'converts name of attributes to Symbol' do e = described_class.new(:e, 'a' => 'v') expect(e.attributes.keys).to eq([:a]) expect(e[:a]).to eq('v') end it 'with block' do base = nil e = described_class.new('base') do |b| b['attr'] = 'value' b << described_class.new('sub') base = b end expect(base.object_id).to eq(e.object_id) e2 = described_class.new('base', attr: 'value') e2 << described_class.new('sub') expect(e2).to eq(e) e = described_class.new('base') do |b| b << described_class.new('sub1') do |s| s << described_class.new('sub12') end b << described_class.new('sub2') end base = described_class.new('base') sub1 = described_class.new('sub1') sub1 << described_class.new('sub12') sub2 = described_class.new('sub2') base << sub1 << sub2 expect(e).to eq(base) end end it '#match' do e = described_class.new(:tag, attr: 'value') expect(e.match(:tag)).to be true expect(e.match(:tag, attr: 'value')).to be true expect(e.match(:t)).to be false expect(e.match(:tag, attr2: 'value')).to be false expect(e.match(:tag, attr: 'value2')).to be false expect(e.match(:tag, attr: /val/)).to be true expect(e.match(described_class.new(:tag))).to be true expect(e.match(described_class.new(:tag, attr: 'value'))).to be true expect(e.match(described_class.new(:tag, attr: /alu/))).to be true expect(e.match(described_class.new(:t))).to be false expect(e.match(described_class.new(:tag, attr2: 'value'))).to be false expect(e.match(described_class.new(:tag, attr: 'value2'))).to be false expect(e.match(described_class.new(:tag, attr: /aul/))).to be false expect(e.match(described_class.new(:tag, attr: PCString.new('value')))).to be true expect(described_class.new(:tag, attr: PCString.new('value'))).to match(e) expect(e.match(described_class.new(:tag, attr: nil))).to be false expect(e.match(described_class.new(:tag, nonattr: nil))).to be true expect(e.match(/ag/)).to eq 1 expect(e.match(/elem/)).to be_nil expect(e.match(described_class)).to be true expect(e.match(dummy_class)).to be false expect(e.match(String)).to be false e = described_class.new(:element) e << described_class.new(:sub) e << 'text' expect(e.match(EDSL.element(:element) { element(:sub) })).to be true expect(e.match(EDSL.element(:element) { element(:other) })).to be false expect(e.match(EDSL.element(:element) { add('text') })).to be true expect(e.match(EDSL.element(:element) { add('other') })).to be false expect(e.match(EDSL.element(:element) { add(/ex/) })).to be true expect(e.match(EDSL.element(:element) { add(/th/) })).to be false expect(e.match(EDSL.element(:element) { add(/sub/) })).to be false e = described_class.new(:t, a: '&') expect(e).to match(described_class.new(:t, a: '&')) expect(e).to match(described_class.new(:t, a: PCString.new('&', true))) expect(e).to match(described_class.new(:t, a: PCString.new('&'))) expect(described_class.new(:t, 'a' => 'v')).to match(described_class.new(:t, a: 'v')) end it '#=~' do e = described_class.new(:tag, attr: 'value', a2: 'v2') expect(e).to match(:tag) expect(e).to match(described_class.new(:tag)) expect(e).to match(described_class.new(:tag, a2: 'v2')) expect(e).to match(described_class.new(:tag, attr: /alu/)) expect(e).to match(described_class.new(:tag, attr: PCString.new('value'))) expect(e).not_to match(:t) expect(e).not_to match(described_class.new(:t)) expect(e).not_to match(described_class.new(:tag, attr: /aul/)) e = described_class.new(:t, a: '&') expect(e).to match(described_class.new(:t, a: '&')) expect(e).to match(described_class.new(:t, a: PCString.new('&', true))) expect(e).to match(described_class.new(:t, a: PCString.new('&'))) end %w[has? has_element? include?].each do |method| it "##{method}" do e = described_class.new(:base) do |b| b << described_class.new(:sub) do |s| s << described_class.new(:deep) do |d| d << 'text' d << PCString.new('&', true) d << '<' end end b << described_class.new(:sub, attr: 'value') end expect(e.send(method, :sub)).to be true expect(e.send(method, :sub, attr: 'value')).to be true expect(e.send(method, :sub, attr: 'value', attr2: '')).to be false expect(e.send(method, :deep)).to be true expect(e.send(method, String)).to be true expect(e.send(method, PCString)).to be true d = described_class.new(:deep) d << 'text' d << PCString.new('&', true) d << '<' expect(e.send(method, d)).to be true d = described_class.new(:deep) d << PCString.new('text', true) d << '&' d << PCString.new('<', true) expect(e.send(method, d)).to be true end end it '#find' do s1 = described_class.new(:sub) d = described_class.new(:deep) d << '3rd' s1 << '2nd' << d s2 = described_class.new(:sub, attr: 'value') e = described_class.new(:base) e << '1st' << s1 << s2 expect(e.find(:deep)).to be_a(described_class) expect(e.find(:deep).name).to eq(:found) expect(e.find(:deep).contents).to eq([d]) expect(e.find(:sub).contents).to eq([s1, s2]) expect(e.find(//).contents).to eq([e, s1, d, s2]) expect(e.find(:sub, attr: 'value').contents).to eq([s2]) expect(e.find(String).contents).to eq(%w[1st 2nd 3rd]) end end end hirakuro-eim_xml-390a16b/spec/formatter_spec.rb000066400000000000000000000153631465336656100216400ustar00rootroot00000000000000require 'eim_xml/formatter' require 'eim_xml/dsl' describe EimXML::Formatter do describe '.write' do it 'returns output object' do s = '' expect(described_class.write(EimXML::Element.new(:e), out: s)).to equal(s) end it 'returns string when destination not given' do r = described_class.write(EimXML::Element.new(:e)) expect(r).to be_a(String) end describe 'should return formatted elements string' do def write(*arg) EimXML::Formatter.write(*arg) end it '(element not have content)' do expect(write(EimXML::DSL.element(:e))).to eq("\n") end it '(empty element which has attributes)' do r = (write(EimXML::DSL.element(:e, a1: 'v1', a2: 'v2')) =~ %r{}) expect(r).not_to be_nil expect([Regexp.last_match(1), Regexp.last_match(2)].sort).to eq(["a1='v1'", "a2='v2'"]) end it '(element in element)' do e = EimXML::DSL.element(:e) do element(:s) end expect(write(e)).to eq <<~XML XML end it '(elements in element)' do e = EimXML::DSL.element(:e) do element(:s1) element(:s2) end expect(write(e)).to eq <<~XML XML end it '(comment in element)' do e = EimXML::DSL.element(:e) do comment("multi\nline\n pre-indented\n comment") end expect(write(e)).to eq <<~XML XML end it '(string in element)' do e = EimXML::Element.new(:e) e.add('string') expect(write(e)).to eq("\n string\n\n") expect(write(EimXML::Element.new(:e, a: "&<>\n'\"").add("&<>\n'\""))).to eq( "\n &<>\n '"\n\n" ) expect(write(EimXML::Element.new(:e, a: "&<>\n'\"").add(EimXML::PCString.new("&<>\n'\"", true)))).to eq( "\n &<>\n '\"\n\n" ) end it '(multi-line string in element)' do e = EimXML::Element.new(:e) e.add("multi\nline") expect(write(e)).to eq <<~XML multi line XML end describe '(preserve spaces' do it 'name of element' do e = EimXML::DSL.element(:e) do element(:pre1) do element(:sub1).add('text') element(:sub2) end element(:pre2).add("multi\nline\ntext") element(:sub1).add('text') end s = <<~XML text multi line text text XML expect(write(e, preservers: %i[pre1 pre2])).to eq(s) end it 'class of element' do m_pre = Class.new(EimXML::Element) do def initialize(name = nil) super(name || 'pre') end end m_p1 = Class.new(m_pre) do def initialize(name = nil) super(name || 'p1') end end m_p2 = Class.new(m_p1) do def initialize super('p2') end end e = EimXML::Element.new(:e) e << m_pre.new.add("text\nwith\nnewline") e << m_pre.new('dummy').add("t\nn") e << m_p1.new.add("t1\nn") e << m_p2.new.add("t2\nn") e << m_pre.new.add(EimXML::Element.new(:s).add("t\ns")) e << m_p2.new.add(EimXML::Element.new(:s).add("t\ns2")) e << EimXML::Element.new(:s).add(EimXML::Element.new(:s).add("t\ns")) s = <<~XML
text
            with
            newline
t n t1 n t2 n
t
            s
t s2 t s
XML expect(write(e, preservers: [m_pre])).to eq(s) end end it '(all)' do s = <<~XML text2 text32 multi-line text sub52 sub54-1 sub54-2 XML e = EimXML::DSL.element(:base) do element(:sub1) element(:sub2).add('text2') element(:sub3, a1: 'v1') do element(:sub31) element(:sub32).add('text32') end element(:sub4).add("multi-line\ntext") element(:sub5) do element(:sub51) add('sub52') element(:sub53) add("sub54-1\nsub54-2") end end expect(write(e)).to eq(s) end end end end describe EimXML::Formatter::ElementWrapper do let(:out) { '' } let(:opt) { { out:, preservers: [], a: 10, b: 20 } } let(:formatter) { EimXML::Formatter.new(opt) } let(:wrapper_class) do Class.new(EimXML::Formatter::ElementWrapper) do def initialize(mocks) super() @mocks = mocks end def contents(_option) @mocks end end end let(:mocks) { [double(:m1).as_null_object, double(:m2).as_null_object] } let(:wrapper) { wrapper_class.new(mocks) } let(:xml) do EimXML::Element.new(:e) do |e| e << wrapper end end describe '#each' do it 'gives options from formatter' do expect(wrapper).to receive(:contents).with(a: 10, b: 20).and_return([]) formatter.write(xml) end it 'yield result of contents' do mocks.each_with_index do |mock, index| expect(mock).to receive(:to_s).and_return("m#{index}") end formatter.write(xml) expect(out).to eq("\n m0\n m1\n\n") end it 'raise error when subclass of ElementWrapper is not implement #contents' do wrapper_class2 = Class.new(described_class) xml << wrapper_class2.new expect { formatter.write(xml) }.to raise_error(NoMethodError) end end end hirakuro-eim_xml-390a16b/spec/helper_coverage.rb000066400000000000000000000001641465336656100217460ustar00rootroot00000000000000require 'simplecov' SimpleCov.start :bundler_filter do add_filter '/gems/' track_files 'spec/**/*_spec.rb' end hirakuro-eim_xml-390a16b/spec/parser_spec.rb000066400000000000000000000065251465336656100211310ustar00rootroot00000000000000require 'eim_xml/parser' module Module.new::M # rubocop:disable Style/ClassAndModuleChildren include EimXML describe Parser do def parse(src) Parser.new(src).parse end it "'parser' method for test" do s = ' ' expect(parse(s)).to eq(described_class.new(s).parse) end it '#parse with empty element' do expect(parse('')).to eq(Element.new('e')) expect(parse('')).to eq(Element.new('e')) expect(parse(%())).to eq(Element.new('e', key: 'value')) expect(parse(%())).to eq(Element.new('e', key: 'value')) expect(parse(%())).to eq(Element.new('e', key: 'value')) expect(parse(%())).to eq(Element.new('e', key: 'value')) expect(parse(%())).to eq(Element.new('e', key: 'value', key2: 'value2')) expect(parse(%())).to eq(Element.new('e', key: 'value', key2: 'value2')) s = ' ' p = described_class.new(s) expect(p.parse).to eq(PCString.new(' ')) expect(p.parse).to eq(Element.new('e1')) expect(p.parse).to eq(PCString.new(' ')) expect(p.parse).to eq(Element.new('e2')) end it '#parse with nonempty element' do expect(parse('')).to eq(Element.new('super') << Element.new('sub')) expect(parse('')).to eq(Element.new('out') << Element.new('in')) expect { parse('') }.to raise_error(ParseError, 'End tag mismatched.') expect { parse('<>') }.to raise_error(ParseError, 'Syntax error.') end it '#parse with string' do e = parse('string&') expect(e).to be_a(PCString) expect(e.to_s).to eq('string&') e = parse(' string & ') expect(e).to be_a(PCString) expect(e.to_s).to eq(' string & ') e = Element.new('e') e << PCString.new(' string ') expect(parse(' string ')).to eq(e) e = Element.new('e') e << PCString.new('string') expect(parse('string')).to eq(e) end it '#parse escaped characters' do e = parse('&"'<>') expect(e.to_s).to eq('&"'<>') expect(e.src).to eq("&\"'<>") end it '#parse with holding space' do s = " string with space\n" e = Element.new('e') e << PCString.new(" string with space\n") expect(parse(s)).to eq(e) expect(parse(s).to_s).to eq(s) s = " string with space\n" e = Element.new('ns:e') e << PCString.new(" string with space\n") expect(parse(s)).to eq(e) expect(parse(s).to_s).to eq(s) s = ' string without space string with space string with space 2 ' oa = Element.new('a') << PCString.new(' string without space ') b = Element.new('b') b << PCString.new(' string with space ') ia = Element.new('a') ia << PCString.new(' string with space 2 ') b << ia b << PCString.new(' ') oa << b oa << PCString.new(' ') expect(parse(s)).to eq(oa) expect(parse(s).to_s).to eq(s) s = '' a = Element.new('a') b = Element.new('b') a << b expect(parse(s)).to eq(a) expect(parse(s).to_s).to eq('') end end end hirakuro-eim_xml-390a16b/spec/spec_helper.rb000066400000000000000000000012361465336656100211060ustar00rootroot00000000000000# This file was generated by the `rspec --init` command. Conventionally, all # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. # Require this file using `require "spec_helper"` to ensure that it is only # loaded once. # # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration RSpec.configure do |config| config.run_all_when_everything_filtered = true config.filter_run :focus # Run specs in random order to surface order dependencies. If you find an # order dependency and want to debug it, you can fix the order by providing # the seed, which is printed after each run. # --seed 1234 config.order = 'random' end hirakuro-eim_xml-390a16b/spec/xhtml_spec.rb000066400000000000000000000370041465336656100207650ustar00rootroot00000000000000require 'stringio' require 'eim_xml/xhtml/dsl' module Module.new::M # rubocop:disable Style/ClassAndModuleChildren include EimXML include EimXML::XHTML XDSL = XHTML::DSL describe XHTML do it 'DSL.base_ should raise NoMethodError' do expect { XDSL.base_ }.to raise_error(NoMethodError) end it 'HTML' do h = HTML.new(attr: 'value') expect(h).to eq(Element.new(:html, attr: 'value')) h = HTML.new do |e| e << Element.new(:sub) end h2 = HTML.new h2 << Element.new(:sub) expect(h2).to eq(h) expect { EimXML::DSL.html }.to raise_error(NoMethodError) expect(XDSL.html(key: 'v')).to eq(HTML.new(key: 'v')) expect(OpenDSL.html(key: 'v')).to eq(HTML.new(key: 'v')) h = HTML.new expect(h.write_to).to eq('') h.prefix = '' expect(h.write_to).to eq(%(\n)) end it 'HEAD' do expect(HEAD.new.name).to eq(:head) expect(XDSL.head).to be_a(HEAD) expect(OpenDSL.head).to be_a(HEAD) end it 'META' do expect(META.new.name).to eq(:meta) expect(XDSL.meta).to be_a(META) expect(OpenDSL.meta).to be_a(META) end it 'LINK' do expect(LINK.new.name).to eq(:link) expect(XDSL.link).to be_a(LINK) expect(OpenDSL.link).to be_a(LINK) end it 'STYLE' do expect(STYLE.new.name).to eq(:style) expect(XDSL.style).to be_a(STYLE) expect(OpenDSL.style).to be_a(STYLE) end it 'IMG' do expect(IMG.new.name).to eq(:img) expect(XDSL.img).to be_a(IMG) expect(OpenDSL.img).to be_a(IMG) end it 'SCRIPT' do expect(SCRIPT.new.name).to eq(:script) expect(XDSL.script).to be_a(SCRIPT) expect(OpenDSL.script).to be_a(SCRIPT) end it 'TITLE' do expect(TITLE.new.name).to eq(:title) expect(XDSL.title).to be_a(TITLE) expect(OpenDSL.title).to be_a(TITLE) end it 'BODY' do expect(BODY.new.name).to eq(:body) expect(XDSL.body).to be_a(BODY) expect(OpenDSL.body).to be_a(BODY) end it 'PRE' do expect(PRE.new.name).to eq(:pre) expect(XDSL.pre).to be_a(PRE) expect(OpenDSL.pre).to be_a(PRE) end it 'Hn' do h1 = Hn.new(1) h6 = Hn.new(6) expect(h1.name).to eq(:h1) expect(h1).to be_a(H1) expect(h6.name).to eq(:h6) expect(h6).to be_a(H6) expect { Hn.new(7) }.to raise_error(ArgumentError) expect { Hn.new(0) }.to raise_error(ArgumentError) h = Hn.new(1, key: :value) do |hn| hn << 'test' end expect(h[:key]).to eq(:value) expect(h[0]).to eq('test') [ [H1, XDSL.h1, OpenDSL.h1], [H2, XDSL.h2, OpenDSL.h2], [H3, XDSL.h3, OpenDSL.h3], [H4, XDSL.h4, OpenDSL.h4], [H5, XDSL.h5, OpenDSL.h5], [H6, XDSL.h6, OpenDSL.h6] ].each do |klass, dsl, od| expect(dsl).to be_a(klass) expect(od).to be_a(klass) end end it 'P' do expect(P.new.name).to eq(:p) expect(XDSL.p).to be_a(P) expect(OpenDSL.p).to be_a(P) end it 'A' do expect(A.new.name).to eq(:a) expect(XDSL.a).to be_a(A) expect(OpenDSL.a).to be_a(A) end it 'EM' do expect(EM.new.name).to eq(:em) expect(XDSL.em).to be_a(EM) expect(OpenDSL.em).to be_a(EM) end it 'STRONG' do expect(STRONG.new.name).to eq(:strong) expect(XDSL.strong).to be_a(STRONG) expect(OpenDSL.strong).to be_a(STRONG) end it 'DIV' do expect(DIV.new.name).to eq(:div) expect(XDSL.div).to be_a(DIV) expect(OpenDSL.div).to be_a(DIV) end it 'SPAN' do expect(SPAN.new.name).to eq(:span) expect(XDSL.span).to be_a(SPAN) expect(OpenDSL.span).to be_a(SPAN) end it 'UL' do expect(UL.new.name).to eq(:ul) expect(XDSL.ul).to be_a(UL) expect(OpenDSL.ul).to be_a(UL) end it 'OL' do expect(OL.new.name).to eq(:ol) expect(XDSL.ol).to be_a(OL) expect(OpenDSL.ol).to be_a(OL) end it 'LI' do expect(LI.new.name).to eq(:li) expect(XDSL.li).to be_a(LI) expect(OpenDSL.li).to be_a(LI) end it 'DL' do expect(DL.new.name).to eq(:dl) expect(XDSL.dl).to be_a(DL) expect(OpenDSL.dl).to be_a(DL) end it 'DT' do expect(DT.new.name).to eq(:dt) expect(XDSL.dt).to be_a(DT) expect(OpenDSL.dt).to be_a(DT) end it 'DD' do expect(DD.new.name).to eq(:dd) expect(XDSL.dd).to be_a(DD) expect(OpenDSL.dd).to be_a(DD) end it 'TABLE' do expect(TABLE.new.name).to eq(:table) expect(XDSL.table).to be_a(TABLE) expect(OpenDSL.table).to be_a(TABLE) end it 'CAPTION' do expect(CAPTION.new.name).to eq(:caption) expect(XDSL.caption).to be_a(CAPTION) expect(OpenDSL.caption).to be_a(CAPTION) end it 'TR' do expect(TR.new.name).to eq(:tr) expect(XDSL.tr).to be_a(TR) expect(OpenDSL.tr).to be_a(TR) end it 'TH' do expect(TH.new.name).to eq(:th) expect(XDSL.th).to be_a(TH) expect(OpenDSL.th).to be_a(TH) end it 'TD' do expect(TD.new.name).to eq(:td) expect(XDSL.td).to be_a(TD) expect(OpenDSL.td).to be_a(TD) end it 'FORM' do expect(FORM.new.name).to eq(:form) expect(XDSL.form).to be_a(FORM) expect(OpenDSL.form).to be_a(FORM) expect(FORM.new).not_to include(HIDDEN) end it 'FORM.new should be able to receive CGI::Session object and set random token' do s = double('session') h = {} expect(s).to receive(:[]).at_least(:once) expect(s).to(receive(:[]=).at_least(:once)) { |k, v| h[k] = v } f = FORM.new(session: s) expect(h['token'].size).to eq(40) expect(h['token']).to match(/\A[0-9a-f]{40}\z/) expect(f).to include(HIDDEN.new(name: 'token', value: h['token'])) s = double('session') h = {} expect(s).to(receive(:[]).at_least(:once)) expect(s).to(receive(:[]=).at_least(:once)) { |k, v| h[k] = v } f = FORM.new(session: s, session_name: 'random_key') expect(h['token']).to be_nil expect(h['random_key'].size).to eq(40) expect(h['random_key']).to match(/\A[0-9a-f]{40}\z/) expect(f).to include(HIDDEN.new(name: 'random_key', value: h['random_key'])) s = double('session') h = {} expect(s).to(receive(:[]).at_least(:once)) { |k| h[k] } expect(s).to(receive(:[]=).at_least(:once)) { |k, v| h[k] = v } FORM.new(session: s) token = s['token'] expect(FORM.new(session: s)).to include(HIDDEN.new(name: 'token', value: token)) expect(s['token']).to eq(token) end it 'TEXTAREA' do expect(TEXTAREA.new(name: 'item')).to eq(Element.new(:textarea, name: 'item')) expect(TEXTAREA.new(name: :item)).to eq(Element.new(:textarea, name: :item)) expect(TEXTAREA.new(name: 'item', class: 'cv')).to eq(Element.new(:textarea, name: 'item', class: 'cv')) t = XDSL.textarea(name: 't') expect(t).to be_a(TEXTAREA) expect(t[:name]).to eq('t') t = OpenDSL.textarea(name: 't') expect(t).to be_a(TEXTAREA) expect(t[:name]).to eq('t') end it 'BUTTON' do expect(BUTTON.new).to eq(Element.new(:button)) end it 'INPUT' do expect(INPUT.new(type: :test, name: :item, value: 'v')) .to eq(Element.new(:input, type: :test, name: :item, value: 'v')) expect(INPUT.new(type: 'test', name: 'item', value: 'v')) .to eq(Element.new(:input, type: 'test', name: 'item', value: 'v')) expect(INPUT.new(type: :test, name: :item, value: 'v', class: 'c')) .to eq(Element.new(:input, type: :test, name: :item, value: 'v', class: 'c')) expect(INPUT.new(type: :submit, value: 'v')).to eq(Element.new(:input, type: :submit, value: 'v')) expect(INPUT.new(type: :submit, name: 'item')).to eq(Element.new(:input, type: :submit, name: 'item')) i = XDSL.input(type: :dummy, name: :n, value: :v) expect(i).to be_a(INPUT) expect(i).to match(INPUT.new(type: :dummy, name: :n, value: :v)) i = OpenDSL.input(type: :dummy, name: :n, value: :v) expect(i).to be_a(INPUT) expect(i).to eq(INPUT.new(type: :dummy, name: :n, value: :v)) end it 'HIDDEN' do expect(HIDDEN.new(name: 'item', value: 'v')).to eq(Element.new(:input, type: :hidden, name: 'item', value: 'v')) expect(HIDDEN.new(name: :item, value: 'v')).to eq(Element.new(:input, type: :hidden, name: :item, value: 'v')) expect(HIDDEN.new(name: :item, value: 'v', class: 'c')) .to eq(Element.new(:input, type: :hidden, name: :item, value: 'v', class: 'c')) h = XDSL.hidden(name: :n, value: :v) expect(h).to be_a(HIDDEN) expect(h).to match(HIDDEN.new(name: :n, value: :v)) h = OpenDSL.hidden(name: :n, value: :v) expect(h).to be_a(HIDDEN) expect(h).to eq(HIDDEN.new(name: :n, value: :v)) end it 'SUBMIT' do expect(SUBMIT.new).to eq(Element.new(:button, type: :submit)) expect(SUBMIT.new(value: 'OK')).to eq(Element.new(:button, type: :submit, value: 'OK')) expect(SUBMIT.new(value: 'OK', class: 'c')).to eq(Element.new(:button, type: :submit, value: 'OK', class: 'c')) opt = { value: 'v', name: 'n' } opt2 = opt.dup SUBMIT.new(opt2) expect(opt2).to eq(opt) s = XDSL.submit expect(s).to be_a(SUBMIT) expect(s).to match(SUBMIT.new) expect(!s[:name]).to be true expect(!s[:value]).to be true s = XDSL.submit(name: :s, value: :v) expect(s[:name]).to eq(:s) expect(s[:value]).to eq(:v) s = OpenDSL.submit expect(s).to be_a(SUBMIT) expect(s).to eq(SUBMIT.new) expect(s[:name]).to be_nil expect(s[:value]).to be_nil s = OpenDSL.submit(name: :s, value: :v) expect(s).to eq(SUBMIT.new(name: :s, value: :v)) end it 'TEXT' do expect(TEXT.new(name: :item)).to eq(Element.new(:input, type: :text, name: :item)) expect(TEXT.new(name: 'item')).to eq(Element.new(:input, type: :text, name: 'item')) expect(TEXT.new(name: :item, value: 'txt')).to eq(Element.new(:input, type: :text, name: :item, value: 'txt')) expect(TEXT.new(name: :item, value: 'txt', class: 'c')).to eq(Element.new(:input, type: :text, name: :item, value: 'txt', class: 'c')) t = XDSL.text(name: :n, value: :v) expect(t).to be_a(TEXT) expect(t).to match(TEXT.new(name: :n, value: :v)) t = OpenDSL.text(name: :n, value: :v) expect(t).to be_a(TEXT) expect(t).to eq(TEXT.new(name: :n, value: :v)) end it 'PASSWORD' do expect(PASSWORD.new(name: :item)).to eq(Element.new(:input, type: :password, name: :item)) expect(PASSWORD.new(name: 'item')).to eq(Element.new(:input, type: :password, name: 'item')) expect(PASSWORD.new(name: :item, value: 'txt')).to eq(Element.new(:input, type: :password, name: :item, value: 'txt')) expect(PASSWORD.new(name: :item, value: 'txt', class: 'c')).to eq(Element.new(:input, type: :password, name: :item, value: 'txt', class: 'c')) t = XDSL.password(name: :n, value: :v) expect(t).to be_a(PASSWORD) expect(t).to match(PASSWORD.new(name: :n, value: :v)) t = OpenDSL.password(name: :n, value: :v) expect(t).to be_a(PASSWORD) expect(t).to eq(PASSWORD.new(name: :n, value: :v)) end it 'FILE' do expect(FILE.new(name: :foo)).to eq(Element.new(:input, type: :file, name: :foo)) expect(XDSL.file(name: :foo)).to match(FILE.new(name: :foo)) expect(OpenDSL.file(name: :foo)).to eq(FILE.new(name: :foo)) end it 'SELECT' do expect(SELECT.new(name: :foo)).to eq(Element.new(:select, name: :foo)) expect(XDSL.select(name: :foo)).to eq(SELECT.new(name: :foo)) expect(OpenDSL.select(name: :foo)).to eq(SELECT.new(name: :foo)) end it 'OPTION' do expect(OPTION.new(value: :bar, selected: true) do |e| e << 'TEXT' end).to eq(Element.new(:option, value: :bar, selected: true) do |e| e.add('TEXT') end) expect(XDSL.option(value: :bar)).to eq(OPTION.new(value: :bar)) expect(OpenDSL.option(value: :bar)).to eq(OPTION.new(value: :bar)) end it 'BR' do expect(BR.new.name).to eq(:br) expect(XDSL.br).to be_a(BR) expect(OpenDSL.br).to be_a(BR) end it 'HR' do expect(HR.new.name).to eq(:hr) expect(XDSL.hr).to be_a(HR) expect(OpenDSL.hr).to be_a(HR) end end describe EimXML::XHTML::OpenDSL do it 'replace EimXML::XHTML::DSL' do e = described_class.html do |d| d.head do d.title.add 'Title' end d.body do d.h1.add 'Sample' d.p do d.add 'text' d.add 'next' end end end expect(e).to eq(EimXML::XHTML::DSL.html do head do title.add 'Title' end body do h1.add 'Sample' p do add 'text' add 'next' end end end) end end describe EimXML::XHTML::Formatter do describe '#write' do it 'sets :preservers=>PRESERVE_SPACES to default option' do e = EimXML::XHTML::HTML.new expect(EimXML::Formatter).to receive(:write).with(e, preservers: EimXML::XHTML::PRESERVE_SPACES, opt: :dummy) described_class.write(e, opt: :dummy) end it 'returns string' do h = EimXML::XHTML::DSL.html do head do style.add("style\ntext") script.add("script\ntext") end body do div.add("text\nin\ndiv") pre.add("pre\nt") h1.add("1\nt") h2.add("2\nt") h3.add("3\nt") h4.add("4\nt") h5.add("5\nt") h6.add("6\nt") p.add("p\nt") a.add("a\nt") em.add("e\nt") strong.add("s\nt") span.add("sp\nt") li.add("li\nt") dt.add("dt\nt") dd.add("dd\nt") caption.add("c\nt") th.add("th\nt") td.add("td\nt") button.add("button\nt") end end s = <<~XML
text in div
pre
          t

1 t

2 t

3 t

4 t

5 t
6 t

p t

a t e t s t sp t
  • li t
  • dt t
    dd t
    c t th t td t XML expect(described_class.write(h)).to eq(s) end end end end